- Andries Brouwer: final isofs pieces.
[davej-history.git] / kernel / sysctl.c
blob3fdf03c342c455e8bd5122249049bc579164217c
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 C_A_D;
45 extern int bdf_prm[], bdflush_min[], bdflush_max[];
46 extern int sysctl_overcommit_memory;
47 extern int max_threads;
48 extern int nr_queued_signals, max_queued_signals;
49 extern int sysrq_enabled;
51 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
52 static int maxolduid = 65535;
53 static int minolduid;
55 #ifdef CONFIG_KMOD
56 extern char modprobe_path[];
57 #endif
58 #ifdef CONFIG_HOTPLUG
59 extern char hotplug_path[];
60 #endif
61 #ifdef CONFIG_CHR_DEV_SG
62 extern int sg_big_buff;
63 #endif
64 #ifdef CONFIG_SYSVIPC
65 extern size_t shm_ctlmax;
66 extern int msg_ctlmax;
67 extern int msg_ctlmnb;
68 extern int msg_ctlmni;
69 extern int sem_ctls[];
70 #endif
72 #ifdef __sparc__
73 extern char reboot_command [];
74 extern int stop_a_enabled;
75 #endif
76 #ifdef __powerpc__
77 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
78 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
79 void *buffer, size_t *lenp);
80 #endif
82 #ifdef CONFIG_BSD_PROCESS_ACCT
83 extern int acct_parm[];
84 #endif
86 extern int pgt_cache_water[];
88 static int parse_table(int *, int, void *, size_t *, void *, size_t,
89 ctl_table *, void **);
90 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
91 void *buffer, size_t *lenp);
93 static ctl_table root_table[];
94 static struct ctl_table_header root_table_header =
95 { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
97 static ctl_table kern_table[];
98 static ctl_table vm_table[];
99 #ifdef CONFIG_NET
100 extern ctl_table net_table[];
101 #endif
102 static ctl_table proc_table[];
103 static ctl_table fs_table[];
104 static ctl_table debug_table[];
105 static ctl_table dev_table[];
106 extern ctl_table random_table[];
108 /* /proc declarations: */
110 #ifdef CONFIG_PROC_FS
112 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
113 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
114 static int proc_sys_permission(struct inode *, int);
116 struct file_operations proc_sys_file_operations = {
117 read: proc_readsys,
118 write: proc_writesys,
121 static struct inode_operations proc_sys_inode_operations = {
122 permission: proc_sys_permission,
125 extern struct proc_dir_entry *proc_sys_root;
127 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
128 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
129 #endif
131 extern int inodes_stat[];
132 extern int dentry_stat[];
134 /* The default sysctl tables: */
136 static ctl_table root_table[] = {
137 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
138 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
139 #ifdef CONFIG_NET
140 {CTL_NET, "net", NULL, 0, 0555, net_table},
141 #endif
142 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
143 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
144 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
145 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
149 static ctl_table kern_table[] = {
150 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
151 0444, NULL, &proc_doutsstring, &sysctl_string},
152 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
153 0444, NULL, &proc_doutsstring, &sysctl_string},
154 {KERN_VERSION, "version", system_utsname.version, 64,
155 0444, NULL, &proc_doutsstring, &sysctl_string},
156 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
157 0644, NULL, &proc_doutsstring, &sysctl_string},
158 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
159 0644, NULL, &proc_doutsstring, &sysctl_string},
160 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
161 0644, NULL, &proc_dointvec},
162 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
163 0600, NULL, &proc_dointvec_bset},
164 #ifdef CONFIG_BLK_DEV_INITRD
165 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
166 0644, NULL, &proc_dointvec},
167 #endif
168 #ifdef __sparc__
169 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
170 256, 0644, NULL, &proc_dostring, &sysctl_string },
171 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
172 0644, NULL, &proc_dointvec},
173 #endif
174 #ifdef __powerpc__
175 {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
176 0644, NULL, &proc_dointvec},
177 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
178 0644, NULL, &proc_dointvec},
179 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
180 0644, NULL, &proc_dointvec},
181 {KERN_PPC_L2CR, "l2cr", NULL, 0,
182 0644, NULL, &proc_dol2crvec},
183 #endif
184 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
185 0644, NULL, &proc_dointvec},
186 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
187 0644, NULL, &proc_dointvec},
188 #ifdef CONFIG_KMOD
189 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
190 0644, NULL, &proc_dostring, &sysctl_string },
191 #endif
192 #ifdef CONFIG_HOTPLUG
193 {KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
194 0644, NULL, &proc_dostring, &sysctl_string },
195 #endif
196 #ifdef CONFIG_CHR_DEV_SG
197 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
198 0444, NULL, &proc_dointvec},
199 #endif
200 #ifdef CONFIG_BSD_PROCESS_ACCT
201 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
202 0644, NULL, &proc_dointvec},
203 #endif
204 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
205 0444, NULL, &proc_dointvec},
206 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
207 0644, NULL, &proc_dointvec},
208 #ifdef CONFIG_SYSVIPC
209 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
210 0644, NULL, &proc_doulongvec_minmax},
211 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
212 0644, NULL, &proc_dointvec},
213 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
214 0644, NULL, &proc_dointvec},
215 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
216 0644, NULL, &proc_dointvec},
217 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
218 0644, NULL, &proc_dointvec},
219 #endif
220 #ifdef CONFIG_MAGIC_SYSRQ
221 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
222 0644, NULL, &proc_dointvec},
223 #endif
224 {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
225 0644, NULL, &proc_dointvec},
226 {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
227 {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
228 &proc_dointvec_minmax, &sysctl_intvec, NULL,
229 &minolduid, &maxolduid},
230 {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
231 &proc_dointvec_minmax, &sysctl_intvec, NULL,
232 &minolduid, &maxolduid},
236 static ctl_table vm_table[] = {
237 {VM_FREEPG, "freepages",
238 &freepages, sizeof(freepages_t), 0444, NULL, &proc_dointvec},
239 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
240 &proc_dointvec_minmax, &sysctl_intvec, NULL,
241 &bdflush_min, &bdflush_max},
242 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
243 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
244 {VM_BUFFERMEM, "buffermem",
245 &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
246 {VM_PAGECACHE, "pagecache",
247 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
248 {VM_PAGERDAEMON, "kswapd",
249 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
250 {VM_PGT_CACHE, "pagetable_cache",
251 &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
252 {VM_PAGE_CLUSTER, "page-cluster",
253 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
257 static ctl_table proc_table[] = {
261 static ctl_table fs_table[] = {
262 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
263 0444, NULL, &proc_dointvec},
264 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
265 0444, NULL, &proc_dointvec},
266 {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
267 0444, NULL, &proc_dointvec},
268 {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
269 0644, NULL, &proc_dointvec},
270 {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
271 0444, NULL, &proc_dointvec},
272 {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
273 0644, NULL, &proc_dointvec},
274 {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
275 0444, NULL, &proc_dointvec},
276 {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
277 0644, NULL, &proc_dointvec},
278 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
279 0444, NULL, &proc_dointvec},
280 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
281 &proc_dointvec_minmax, &sysctl_intvec, NULL,
282 &minolduid, &maxolduid},
283 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
284 &proc_dointvec_minmax, &sysctl_intvec, NULL,
285 &minolduid, &maxolduid},
286 {FS_LEASES, "leases-enable", &leases_enable, sizeof(int),
287 0644, NULL, &proc_dointvec},
288 {FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable,
289 sizeof(int), 0644, NULL, &proc_dointvec},
290 {FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int),
291 0644, NULL, &proc_dointvec},
295 static ctl_table debug_table[] = {
299 static ctl_table dev_table[] = {
303 extern void init_irq_proc (void);
305 void __init sysctl_init(void)
307 #ifdef CONFIG_PROC_FS
308 register_proc_table(root_table, proc_sys_root);
309 init_irq_proc();
310 #endif
313 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
314 void *newval, size_t newlen)
316 struct list_head *tmp;
318 if (nlen == 0 || nlen >= CTL_MAXNAME)
319 return -ENOTDIR;
320 if (oldval) {
321 int old_len;
322 if (!oldlenp || get_user(old_len, oldlenp))
323 return -EFAULT;
325 tmp = &root_table_header.ctl_entry;
326 do {
327 struct ctl_table_header *head =
328 list_entry(tmp, struct ctl_table_header, ctl_entry);
329 void *context = NULL;
330 int error = parse_table(name, nlen, oldval, oldlenp,
331 newval, newlen, head->ctl_table,
332 &context);
333 if (context)
334 kfree(context);
335 if (error != -ENOTDIR)
336 return error;
337 tmp = tmp->next;
338 } while (tmp != &root_table_header.ctl_entry);
339 return -ENOTDIR;
342 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
344 struct __sysctl_args tmp;
345 int error;
347 if (copy_from_user(&tmp, args, sizeof(tmp)))
348 return -EFAULT;
350 lock_kernel();
351 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
352 tmp.newval, tmp.newlen);
353 unlock_kernel();
354 return error;
358 * ctl_perm does NOT grant the superuser all rights automatically, because
359 * some sysctl variables are readonly even to root.
362 static int test_perm(int mode, int op)
364 if (!current->euid)
365 mode >>= 6;
366 else if (in_egroup_p(0))
367 mode >>= 3;
368 if ((mode & op & 0007) == op)
369 return 0;
370 return -EACCES;
373 static inline int ctl_perm(ctl_table *table, int op)
375 return test_perm(table->mode, op);
378 static int parse_table(int *name, int nlen,
379 void *oldval, size_t *oldlenp,
380 void *newval, size_t newlen,
381 ctl_table *table, void **context)
383 int n;
384 repeat:
385 if (!nlen)
386 return -ENOTDIR;
387 if (get_user(n, name))
388 return -EFAULT;
389 for ( ; table->ctl_name; table++) {
390 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
391 int error;
392 if (table->child) {
393 if (ctl_perm(table, 001))
394 return -EPERM;
395 if (table->strategy) {
396 error = table->strategy(
397 table, name, nlen,
398 oldval, oldlenp,
399 newval, newlen, context);
400 if (error)
401 return error;
403 name++;
404 nlen--;
405 table = table->child;
406 goto repeat;
408 error = do_sysctl_strategy(table, name, nlen,
409 oldval, oldlenp,
410 newval, newlen, context);
411 return error;
414 return -ENOTDIR;
417 /* Perform the actual read/write of a sysctl table entry. */
418 int do_sysctl_strategy (ctl_table *table,
419 int *name, int nlen,
420 void *oldval, size_t *oldlenp,
421 void *newval, size_t newlen, void **context)
423 int op = 0, rc, len;
425 if (oldval)
426 op |= 004;
427 if (newval)
428 op |= 002;
429 if (ctl_perm(table, op))
430 return -EPERM;
432 if (table->strategy) {
433 rc = table->strategy(table, name, nlen, oldval, oldlenp,
434 newval, newlen, context);
435 if (rc < 0)
436 return rc;
437 if (rc > 0)
438 return 0;
441 /* If there is no strategy routine, or if the strategy returns
442 * zero, proceed with automatic r/w */
443 if (table->data && table->maxlen) {
444 if (oldval && oldlenp) {
445 get_user(len, oldlenp);
446 if (len) {
447 if (len > table->maxlen)
448 len = table->maxlen;
449 if(copy_to_user(oldval, table->data, len))
450 return -EFAULT;
451 if(put_user(len, oldlenp))
452 return -EFAULT;
455 if (newval && newlen) {
456 len = newlen;
457 if (len > table->maxlen)
458 len = table->maxlen;
459 if(copy_from_user(table->data, newval, len))
460 return -EFAULT;
463 return 0;
466 struct ctl_table_header *register_sysctl_table(ctl_table * table,
467 int insert_at_head)
469 struct ctl_table_header *tmp;
470 tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
471 if (!tmp)
472 return 0;
473 tmp->ctl_table = table;
474 INIT_LIST_HEAD(&tmp->ctl_entry);
475 if (insert_at_head)
476 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
477 else
478 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
479 #ifdef CONFIG_PROC_FS
480 register_proc_table(table, proc_sys_root);
481 #endif
482 return tmp;
486 * Unlink and free a ctl_table.
488 void unregister_sysctl_table(struct ctl_table_header * header)
490 list_del(&header->ctl_entry);
491 #ifdef CONFIG_PROC_FS
492 unregister_proc_table(header->ctl_table, proc_sys_root);
493 #endif
494 kfree(header);
498 * /proc/sys support
501 #ifdef CONFIG_PROC_FS
503 /* Scan the sysctl entries in table and add them all into /proc */
504 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
506 struct proc_dir_entry *de;
507 int len;
508 mode_t mode;
510 for (; table->ctl_name; table++) {
511 /* Can't do anything without a proc name. */
512 if (!table->procname)
513 continue;
514 /* Maybe we can't do anything with it... */
515 if (!table->proc_handler && !table->child) {
516 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
517 table->procname);
518 continue;
521 len = strlen(table->procname);
522 mode = table->mode;
524 de = NULL;
525 if (table->proc_handler)
526 mode |= S_IFREG;
527 else {
528 mode |= S_IFDIR;
529 for (de = root->subdir; de; de = de->next) {
530 if (proc_match(len, table->procname, de))
531 break;
533 /* If the subdir exists already, de is non-NULL */
536 if (!de) {
537 de = create_proc_entry(table->procname, mode, root);
538 if (!de)
539 continue;
540 de->data = (void *) table;
541 if (table->proc_handler) {
542 de->proc_fops = &proc_sys_file_operations;
543 de->proc_iops = &proc_sys_inode_operations;
546 table->de = de;
547 if (de->mode & S_IFDIR)
548 register_proc_table(table->child, de);
553 * Unregister a /proc sysctl table and any subdirectories.
555 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
557 struct proc_dir_entry *de;
558 for (; table->ctl_name; table++) {
559 if (!(de = table->de))
560 continue;
561 if (de->mode & S_IFDIR) {
562 if (!table->child) {
563 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
564 continue;
566 unregister_proc_table(table->child, de);
568 /* Don't unregister directories which still have entries.. */
569 if (de->subdir)
570 continue;
573 /* Don't unregister proc entries that are still being used.. */
574 if (atomic_read(&de->count))
575 continue;
577 table->de = NULL;
578 remove_proc_entry(table->procname, root);
582 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
583 size_t count, loff_t *ppos)
585 int op;
586 struct proc_dir_entry *de;
587 struct ctl_table *table;
588 size_t res;
589 ssize_t error;
591 de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
592 if (!de || !de->data)
593 return -ENOTDIR;
594 table = (struct ctl_table *) de->data;
595 if (!table || !table->proc_handler)
596 return -ENOTDIR;
597 op = (write ? 002 : 004);
598 if (ctl_perm(table, op))
599 return -EPERM;
601 res = count;
604 * FIXME: we need to pass on ppos to the handler.
607 error = (*table->proc_handler) (table, write, file, buf, &res);
608 if (error)
609 return error;
610 return res;
613 static ssize_t proc_readsys(struct file * file, char * buf,
614 size_t count, loff_t *ppos)
616 return do_rw_proc(0, file, buf, count, ppos);
619 static ssize_t proc_writesys(struct file * file, const char * buf,
620 size_t count, loff_t *ppos)
622 return do_rw_proc(1, file, (char *) buf, count, ppos);
625 static int proc_sys_permission(struct inode *inode, int op)
627 return test_perm(inode->i_mode, op);
630 int proc_dostring(ctl_table *table, int write, struct file *filp,
631 void *buffer, size_t *lenp)
633 int len;
634 char *p, c;
636 if (!table->data || !table->maxlen || !*lenp ||
637 (filp->f_pos && !write)) {
638 *lenp = 0;
639 return 0;
642 if (write) {
643 len = 0;
644 p = buffer;
645 while (len < *lenp) {
646 if(get_user(c, p++))
647 return -EFAULT;
648 if (c == 0 || c == '\n')
649 break;
650 len++;
652 if (len >= table->maxlen)
653 len = table->maxlen-1;
654 if(copy_from_user(table->data, buffer, len))
655 return -EFAULT;
656 ((char *) table->data)[len] = 0;
657 filp->f_pos += *lenp;
658 } else {
659 len = strlen(table->data);
660 if (len > table->maxlen)
661 len = table->maxlen;
662 if (len > *lenp)
663 len = *lenp;
664 if (len)
665 if(copy_to_user(buffer, table->data, len))
666 return -EFAULT;
667 if (len < *lenp) {
668 if(put_user('\n', ((char *) buffer) + len))
669 return -EFAULT;
670 len++;
672 *lenp = len;
673 filp->f_pos += len;
675 return 0;
679 * Special case of dostring for the UTS structure. This has locks
680 * to observe. Should this be in kernel/sys.c ????
683 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
684 void *buffer, size_t *lenp)
686 int r;
688 if (!write) {
689 down_read(&uts_sem);
690 r=proc_dostring(table,0,filp,buffer,lenp);
691 up_read(&uts_sem);
692 } else {
693 down_write(&uts_sem);
694 r=proc_dostring(table,1,filp,buffer,lenp);
695 up_write(&uts_sem);
697 return r;
700 #define OP_SET 0
701 #define OP_AND 1
702 #define OP_OR 2
703 #define OP_MAX 3
704 #define OP_MIN 4
706 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
707 void *buffer, size_t *lenp, int conv, int op)
709 int *i, vleft, first=1, len, left, neg, val;
710 #define TMPBUFLEN 20
711 char buf[TMPBUFLEN], *p;
713 if (!table->data || !table->maxlen || !*lenp ||
714 (filp->f_pos && !write)) {
715 *lenp = 0;
716 return 0;
719 i = (int *) table->data;
720 vleft = table->maxlen / sizeof(int);
721 left = *lenp;
723 for (; left && vleft--; i++, first=0) {
724 if (write) {
725 while (left) {
726 char c;
727 if(get_user(c,(char *) buffer))
728 return -EFAULT;
729 if (!isspace(c))
730 break;
731 left--;
732 ((char *) buffer)++;
734 if (!left)
735 break;
736 neg = 0;
737 len = left;
738 if (len > TMPBUFLEN-1)
739 len = TMPBUFLEN-1;
740 if(copy_from_user(buf, buffer, len))
741 return -EFAULT;
742 buf[len] = 0;
743 p = buf;
744 if (*p == '-' && left > 1) {
745 neg = 1;
746 left--, p++;
748 if (*p < '0' || *p > '9')
749 break;
750 val = simple_strtoul(p, &p, 0) * conv;
751 len = p-buf;
752 if ((len < left) && *p && !isspace(*p))
753 break;
754 if (neg)
755 val = -val;
756 buffer += len;
757 left -= len;
758 switch(op) {
759 case OP_SET: *i = val; break;
760 case OP_AND: *i &= val; break;
761 case OP_OR: *i |= val; break;
762 case OP_MAX: if(*i < val)
763 *i = val;
764 break;
765 case OP_MIN: if(*i > val)
766 *i = val;
767 break;
769 } else {
770 p = buf;
771 if (!first)
772 *p++ = '\t';
773 sprintf(p, "%d", (*i) / conv);
774 len = strlen(buf);
775 if (len > left)
776 len = left;
777 if(copy_to_user(buffer, buf, len))
778 return -EFAULT;
779 left -= len;
780 buffer += len;
784 if (!write && !first && left) {
785 if(put_user('\n', (char *) buffer))
786 return -EFAULT;
787 left--, buffer++;
789 if (write) {
790 p = (char *) buffer;
791 while (left) {
792 char c;
793 if(get_user(c, p++))
794 return -EFAULT;
795 if (!isspace(c))
796 break;
797 left--;
800 if (write && first)
801 return -EINVAL;
802 *lenp -= left;
803 filp->f_pos += *lenp;
804 return 0;
807 int proc_dointvec(ctl_table *table, int write, struct file *filp,
808 void *buffer, size_t *lenp)
810 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
814 * init may raise the set.
817 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
818 void *buffer, size_t *lenp)
820 if (!capable(CAP_SYS_MODULE)) {
821 return -EPERM;
823 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
824 (current->pid == 1) ? OP_SET : OP_AND);
827 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
828 void *buffer, size_t *lenp)
830 int *i, *min, *max, vleft, first=1, len, left, neg, val;
831 #define TMPBUFLEN 20
832 char buf[TMPBUFLEN], *p;
834 if (!table->data || !table->maxlen || !*lenp ||
835 (filp->f_pos && !write)) {
836 *lenp = 0;
837 return 0;
840 i = (int *) table->data;
841 min = (int *) table->extra1;
842 max = (int *) table->extra2;
843 vleft = table->maxlen / sizeof(int);
844 left = *lenp;
846 for (; left && vleft--; i++, first=0) {
847 if (write) {
848 while (left) {
849 char c;
850 if(get_user(c, (char *) buffer))
851 return -EFAULT;
852 if (!isspace(c))
853 break;
854 left--;
855 ((char *) buffer)++;
857 if (!left)
858 break;
859 neg = 0;
860 len = left;
861 if (len > TMPBUFLEN-1)
862 len = TMPBUFLEN-1;
863 if(copy_from_user(buf, buffer, len))
864 return -EFAULT;
865 buf[len] = 0;
866 p = buf;
867 if (*p == '-' && left > 1) {
868 neg = 1;
869 left--, p++;
871 if (*p < '0' || *p > '9')
872 break;
873 val = simple_strtoul(p, &p, 0);
874 len = p-buf;
875 if ((len < left) && *p && !isspace(*p))
876 break;
877 if (neg)
878 val = -val;
879 buffer += len;
880 left -= len;
882 if (min && val < *min++)
883 continue;
884 if (max && val > *max++)
885 continue;
886 *i = val;
887 } else {
888 p = buf;
889 if (!first)
890 *p++ = '\t';
891 sprintf(p, "%d", *i);
892 len = strlen(buf);
893 if (len > left)
894 len = left;
895 if(copy_to_user(buffer, buf, len))
896 return -EFAULT;
897 left -= len;
898 buffer += len;
902 if (!write && !first && left) {
903 if(put_user('\n', (char *) buffer))
904 return -EFAULT;
905 left--, buffer++;
907 if (write) {
908 p = (char *) buffer;
909 while (left) {
910 char c;
911 if(get_user(c, p++))
912 return -EFAULT;
913 if (!isspace(c))
914 break;
915 left--;
918 if (write && first)
919 return -EINVAL;
920 *lenp -= left;
921 filp->f_pos += *lenp;
922 return 0;
926 * an unsigned long function version
929 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
930 struct file *filp,
931 void *buffer, size_t *lenp,
932 unsigned long convmul,
933 unsigned long convdiv)
935 #define TMPBUFLEN 20
936 unsigned long *i, *min, *max, val;
937 int vleft, first=1, len, left, neg;
938 char buf[TMPBUFLEN], *p;
940 if (!table->data || !table->maxlen || !*lenp ||
941 (filp->f_pos && !write)) {
942 *lenp = 0;
943 return 0;
946 i = (unsigned long *) table->data;
947 min = (unsigned long *) table->extra1;
948 max = (unsigned long *) table->extra2;
949 vleft = table->maxlen / sizeof(unsigned long);
950 left = *lenp;
952 for (; left && vleft--; i++, first=0) {
953 if (write) {
954 while (left) {
955 char c;
956 if(get_user(c, (char *) buffer))
957 return -EFAULT;
958 if (!isspace(c))
959 break;
960 left--;
961 ((char *) buffer)++;
963 if (!left)
964 break;
965 neg = 0;
966 len = left;
967 if (len > TMPBUFLEN-1)
968 len = TMPBUFLEN-1;
969 if(copy_from_user(buf, buffer, len))
970 return -EFAULT;
971 buf[len] = 0;
972 p = buf;
973 if (*p == '-' && left > 1) {
974 neg = 1;
975 left--, p++;
977 if (*p < '0' || *p > '9')
978 break;
979 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
980 len = p-buf;
981 if ((len < left) && *p && !isspace(*p))
982 break;
983 if (neg)
984 val = -val;
985 buffer += len;
986 left -= len;
988 if(neg)
989 continue;
990 if (min && val < *min++)
991 continue;
992 if (max && val > *max++)
993 continue;
994 *i = val;
995 } else {
996 p = buf;
997 if (!first)
998 *p++ = '\t';
999 sprintf(p, "%lu", convdiv * (*i) / convmul);
1000 len = strlen(buf);
1001 if (len > left)
1002 len = left;
1003 if(copy_to_user(buffer, buf, len))
1004 return -EFAULT;
1005 left -= len;
1006 buffer += len;
1010 if (!write && !first && left) {
1011 if(put_user('\n', (char *) buffer))
1012 return -EFAULT;
1013 left--, buffer++;
1015 if (write) {
1016 p = (char *) buffer;
1017 while (left) {
1018 char c;
1019 if(get_user(c, p++))
1020 return -EFAULT;
1021 if (!isspace(c))
1022 break;
1023 left--;
1026 if (write && first)
1027 return -EINVAL;
1028 *lenp -= left;
1029 filp->f_pos += *lenp;
1030 return 0;
1031 #undef TMPBUFLEN
1034 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1035 void *buffer, size_t *lenp)
1037 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1040 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1041 struct file *filp,
1042 void *buffer, size_t *lenp)
1044 return do_proc_doulongvec_minmax(table, write, filp, buffer,
1045 lenp, HZ, 1000l);
1049 /* Like proc_dointvec, but converts seconds to jiffies */
1050 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1051 void *buffer, size_t *lenp)
1053 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1056 #else /* CONFIG_PROC_FS */
1058 int proc_dostring(ctl_table *table, int write, struct file *filp,
1059 void *buffer, size_t *lenp)
1061 return -ENOSYS;
1064 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1065 void *buffer, size_t *lenp)
1067 return -ENOSYS;
1070 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1071 void *buffer, size_t *lenp)
1073 return -ENOSYS;
1076 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1077 void *buffer, size_t *lenp)
1079 return -ENOSYS;
1082 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1083 void *buffer, size_t *lenp)
1085 return -ENOSYS;
1088 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1089 void *buffer, size_t *lenp)
1091 return -ENOSYS;
1094 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1095 void *buffer, size_t *lenp)
1097 return -ENOSYS;
1100 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1101 struct file *filp,
1102 void *buffer, size_t *lenp)
1104 return -ENOSYS;
1108 #endif /* CONFIG_PROC_FS */
1112 * General sysctl support routines
1115 /* The generic string strategy routine: */
1116 int sysctl_string(ctl_table *table, int *name, int nlen,
1117 void *oldval, size_t *oldlenp,
1118 void *newval, size_t newlen, void **context)
1120 int l, len;
1122 if (!table->data || !table->maxlen)
1123 return -ENOTDIR;
1125 if (oldval && oldlenp) {
1126 if(get_user(len, oldlenp))
1127 return -EFAULT;
1128 if (len) {
1129 l = strlen(table->data);
1130 if (len > l) len = l;
1131 if (len >= table->maxlen)
1132 len = table->maxlen;
1133 if(copy_to_user(oldval, table->data, len))
1134 return -EFAULT;
1135 if(put_user(0, ((char *) oldval) + len))
1136 return -EFAULT;
1137 if(put_user(len, oldlenp))
1138 return -EFAULT;
1141 if (newval && newlen) {
1142 len = newlen;
1143 if (len > table->maxlen)
1144 len = table->maxlen;
1145 if(copy_from_user(table->data, newval, len))
1146 return -EFAULT;
1147 if (len == table->maxlen)
1148 len--;
1149 ((char *) table->data)[len] = 0;
1151 return 0;
1155 * This function makes sure that all of the integers in the vector
1156 * are between the minimum and maximum values given in the arrays
1157 * table->extra1 and table->extra2, respectively.
1159 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1160 void *oldval, size_t *oldlenp,
1161 void *newval, size_t newlen, void **context)
1163 int i, length, *vec, *min, *max;
1165 if (newval && newlen) {
1166 if (newlen % sizeof(int) != 0)
1167 return -EINVAL;
1169 if (!table->extra1 && !table->extra2)
1170 return 0;
1172 if (newlen > table->maxlen)
1173 newlen = table->maxlen;
1174 length = newlen / sizeof(int);
1176 vec = (int *) newval;
1177 min = (int *) table->extra1;
1178 max = (int *) table->extra2;
1180 for (i = 0; i < length; i++) {
1181 int value;
1182 get_user(value, vec + i);
1183 if (min && value < min[i])
1184 return -EINVAL;
1185 if (max && value > max[i])
1186 return -EINVAL;
1189 return 0;
1192 /* Strategy function to convert jiffies to seconds */
1193 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1194 void *oldval, size_t *oldlenp,
1195 void *newval, size_t newlen, void **context)
1197 if (oldval) {
1198 size_t olen;
1199 if (oldlenp) {
1200 if (get_user(olen, oldlenp))
1201 return -EFAULT;
1202 if (olen!=sizeof(int))
1203 return -EINVAL;
1205 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1206 (oldlenp && put_user(sizeof(int),oldlenp)))
1207 return -EFAULT;
1209 if (newval && newlen) {
1210 int new;
1211 if (newlen != sizeof(int))
1212 return -EINVAL;
1213 if (get_user(new, (int *)newval))
1214 return -EFAULT;
1215 *(int *)(table->data) = new*HZ;
1217 return 1;
1221 #else /* CONFIG_SYSCTL */
1224 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1226 return -ENOSYS;
1229 int sysctl_string(ctl_table *table, int *name, int nlen,
1230 void *oldval, size_t *oldlenp,
1231 void *newval, size_t newlen, void **context)
1233 return -ENOSYS;
1236 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1237 void *oldval, size_t *oldlenp,
1238 void *newval, size_t newlen, void **context)
1240 return -ENOSYS;
1243 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1244 void *oldval, size_t *oldlenp,
1245 void *newval, size_t newlen, void **context)
1247 return -ENOSYS;
1250 int proc_dostring(ctl_table *table, int write, struct file *filp,
1251 void *buffer, size_t *lenp)
1253 return -ENOSYS;
1256 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1257 void *buffer, size_t *lenp)
1259 return -ENOSYS;
1262 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1263 void *buffer, size_t *lenp)
1265 return -ENOSYS;
1268 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1269 void *buffer, size_t *lenp)
1271 return -ENOSYS;
1274 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1275 void *buffer, size_t *lenp)
1277 return -ENOSYS;
1280 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1281 void *buffer, size_t *lenp)
1283 return -ENOSYS;
1286 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1287 struct file *filp,
1288 void *buffer, size_t *lenp)
1290 return -ENOSYS;
1293 struct ctl_table_header * register_sysctl_table(ctl_table * table,
1294 int insert_at_head)
1296 return 0;
1299 void unregister_sysctl_table(struct ctl_table_header * table)
1303 #endif /* CONFIG_SYSCTL */