Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / kernel / sysctl.c
blob1c22d7838dd20bde86ccb95576b89990b94e470f
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 size_t shm_ctlall;
67 extern int shm_ctlmni;
68 extern int msg_ctlmax;
69 extern int msg_ctlmnb;
70 extern int msg_ctlmni;
71 extern int sem_ctls[];
72 #endif
74 #ifdef __sparc__
75 extern char reboot_command [];
76 extern int stop_a_enabled;
77 #endif
78 #ifdef __powerpc__
79 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
80 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
81 void *buffer, size_t *lenp);
82 #endif
84 #ifdef CONFIG_BSD_PROCESS_ACCT
85 extern int acct_parm[];
86 #endif
88 extern int pgt_cache_water[];
90 static int parse_table(int *, int, void *, size_t *, void *, size_t,
91 ctl_table *, void **);
92 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
93 void *buffer, size_t *lenp);
95 static ctl_table root_table[];
96 static struct ctl_table_header root_table_header =
97 { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
99 static ctl_table kern_table[];
100 static ctl_table vm_table[];
101 #ifdef CONFIG_NET
102 extern ctl_table net_table[];
103 #endif
104 static ctl_table proc_table[];
105 static ctl_table fs_table[];
106 static ctl_table debug_table[];
107 static ctl_table dev_table[];
108 extern ctl_table random_table[];
110 /* /proc declarations: */
112 #ifdef CONFIG_PROC_FS
114 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
115 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
116 static int proc_sys_permission(struct inode *, int);
118 struct file_operations proc_sys_file_operations = {
119 read: proc_readsys,
120 write: proc_writesys,
123 static struct inode_operations proc_sys_inode_operations = {
124 permission: proc_sys_permission,
127 extern struct proc_dir_entry *proc_sys_root;
129 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
130 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
131 #endif
133 extern int inodes_stat[];
134 extern int dentry_stat[];
136 /* The default sysctl tables: */
138 static ctl_table root_table[] = {
139 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
140 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
141 #ifdef CONFIG_NET
142 {CTL_NET, "net", NULL, 0, 0555, net_table},
143 #endif
144 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
145 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
146 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
147 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
151 static ctl_table kern_table[] = {
152 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
153 0444, NULL, &proc_doutsstring, &sysctl_string},
154 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
155 0444, NULL, &proc_doutsstring, &sysctl_string},
156 {KERN_VERSION, "version", system_utsname.version, 64,
157 0444, NULL, &proc_doutsstring, &sysctl_string},
158 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
159 0644, NULL, &proc_doutsstring, &sysctl_string},
160 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
161 0644, NULL, &proc_doutsstring, &sysctl_string},
162 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
163 0644, NULL, &proc_dointvec},
164 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
165 0600, NULL, &proc_dointvec_bset},
166 #ifdef CONFIG_BLK_DEV_INITRD
167 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
168 0644, NULL, &proc_dointvec},
169 #endif
170 #ifdef __sparc__
171 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
172 256, 0644, NULL, &proc_dostring, &sysctl_string },
173 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
174 0644, NULL, &proc_dointvec},
175 #endif
176 #ifdef __powerpc__
177 {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
178 0644, NULL, &proc_dointvec},
179 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
180 0644, NULL, &proc_dointvec},
181 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
182 0644, NULL, &proc_dointvec},
183 {KERN_PPC_L2CR, "l2cr", NULL, 0,
184 0644, NULL, &proc_dol2crvec},
185 #endif
186 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
187 0644, NULL, &proc_dointvec},
188 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
189 0644, NULL, &proc_dointvec},
190 #ifdef CONFIG_KMOD
191 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
192 0644, NULL, &proc_dostring, &sysctl_string },
193 #endif
194 #ifdef CONFIG_HOTPLUG
195 {KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
196 0644, NULL, &proc_dostring, &sysctl_string },
197 #endif
198 #ifdef CONFIG_CHR_DEV_SG
199 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
200 0444, NULL, &proc_dointvec},
201 #endif
202 #ifdef CONFIG_BSD_PROCESS_ACCT
203 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
204 0644, NULL, &proc_dointvec},
205 #endif
206 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
207 0444, NULL, &proc_dointvec},
208 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
209 0644, NULL, &proc_dointvec},
210 #ifdef CONFIG_SYSVIPC
211 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
212 0644, NULL, &proc_doulongvec_minmax},
213 {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (size_t),
214 0644, NULL, &proc_doulongvec_minmax},
215 {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
216 0644, NULL, &proc_dointvec},
217 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
218 0644, NULL, &proc_dointvec},
219 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
220 0644, NULL, &proc_dointvec},
221 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
222 0644, NULL, &proc_dointvec},
223 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
224 0644, NULL, &proc_dointvec},
225 #endif
226 #ifdef CONFIG_MAGIC_SYSRQ
227 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
228 0644, NULL, &proc_dointvec},
229 #endif
230 {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
231 0644, NULL, &proc_dointvec},
232 {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
233 {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
234 &proc_dointvec_minmax, &sysctl_intvec, NULL,
235 &minolduid, &maxolduid},
236 {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
237 &proc_dointvec_minmax, &sysctl_intvec, NULL,
238 &minolduid, &maxolduid},
242 static ctl_table vm_table[] = {
243 {VM_FREEPG, "freepages",
244 &freepages, sizeof(freepages_t), 0444, NULL, &proc_dointvec},
245 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
246 &proc_dointvec_minmax, &sysctl_intvec, NULL,
247 &bdflush_min, &bdflush_max},
248 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
249 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
250 {VM_BUFFERMEM, "buffermem",
251 &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
252 {VM_PAGECACHE, "pagecache",
253 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
254 {VM_PAGERDAEMON, "kswapd",
255 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
256 {VM_PGT_CACHE, "pagetable_cache",
257 &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
258 {VM_PAGE_CLUSTER, "page-cluster",
259 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
263 static ctl_table proc_table[] = {
267 static ctl_table fs_table[] = {
268 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
269 0444, NULL, &proc_dointvec},
270 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
271 0444, NULL, &proc_dointvec},
272 {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
273 0444, NULL, &proc_dointvec},
274 {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
275 0644, NULL, &proc_dointvec},
276 {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
277 0444, NULL, &proc_dointvec},
278 {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
279 0644, NULL, &proc_dointvec},
280 {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
281 0444, NULL, &proc_dointvec},
282 {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
283 0644, NULL, &proc_dointvec},
284 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
285 0444, NULL, &proc_dointvec},
286 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
287 &proc_dointvec_minmax, &sysctl_intvec, NULL,
288 &minolduid, &maxolduid},
289 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
290 &proc_dointvec_minmax, &sysctl_intvec, NULL,
291 &minolduid, &maxolduid},
292 {FS_LEASES, "leases-enable", &leases_enable, sizeof(int),
293 0644, NULL, &proc_dointvec},
294 {FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable,
295 sizeof(int), 0644, NULL, &proc_dointvec},
296 {FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int),
297 0644, NULL, &proc_dointvec},
301 static ctl_table debug_table[] = {
305 static ctl_table dev_table[] = {
309 extern void init_irq_proc (void);
311 void __init sysctl_init(void)
313 #ifdef CONFIG_PROC_FS
314 register_proc_table(root_table, proc_sys_root);
315 init_irq_proc();
316 #endif
319 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
320 void *newval, size_t newlen)
322 struct list_head *tmp;
324 if (nlen == 0 || nlen >= CTL_MAXNAME)
325 return -ENOTDIR;
326 if (oldval) {
327 int old_len;
328 if (!oldlenp || get_user(old_len, oldlenp))
329 return -EFAULT;
331 tmp = &root_table_header.ctl_entry;
332 do {
333 struct ctl_table_header *head =
334 list_entry(tmp, struct ctl_table_header, ctl_entry);
335 void *context = NULL;
336 int error = parse_table(name, nlen, oldval, oldlenp,
337 newval, newlen, head->ctl_table,
338 &context);
339 if (context)
340 kfree(context);
341 if (error != -ENOTDIR)
342 return error;
343 tmp = tmp->next;
344 } while (tmp != &root_table_header.ctl_entry);
345 return -ENOTDIR;
348 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
350 struct __sysctl_args tmp;
351 int error;
353 if (copy_from_user(&tmp, args, sizeof(tmp)))
354 return -EFAULT;
356 lock_kernel();
357 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
358 tmp.newval, tmp.newlen);
359 unlock_kernel();
360 return error;
364 * ctl_perm does NOT grant the superuser all rights automatically, because
365 * some sysctl variables are readonly even to root.
368 static int test_perm(int mode, int op)
370 if (!current->euid)
371 mode >>= 6;
372 else if (in_egroup_p(0))
373 mode >>= 3;
374 if ((mode & op & 0007) == op)
375 return 0;
376 return -EACCES;
379 static inline int ctl_perm(ctl_table *table, int op)
381 return test_perm(table->mode, op);
384 static int parse_table(int *name, int nlen,
385 void *oldval, size_t *oldlenp,
386 void *newval, size_t newlen,
387 ctl_table *table, void **context)
389 int n;
390 repeat:
391 if (!nlen)
392 return -ENOTDIR;
393 if (get_user(n, name))
394 return -EFAULT;
395 for ( ; table->ctl_name; table++) {
396 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
397 int error;
398 if (table->child) {
399 if (ctl_perm(table, 001))
400 return -EPERM;
401 if (table->strategy) {
402 error = table->strategy(
403 table, name, nlen,
404 oldval, oldlenp,
405 newval, newlen, context);
406 if (error)
407 return error;
409 name++;
410 nlen--;
411 table = table->child;
412 goto repeat;
414 error = do_sysctl_strategy(table, name, nlen,
415 oldval, oldlenp,
416 newval, newlen, context);
417 return error;
420 return -ENOTDIR;
423 /* Perform the actual read/write of a sysctl table entry. */
424 int do_sysctl_strategy (ctl_table *table,
425 int *name, int nlen,
426 void *oldval, size_t *oldlenp,
427 void *newval, size_t newlen, void **context)
429 int op = 0, rc, len;
431 if (oldval)
432 op |= 004;
433 if (newval)
434 op |= 002;
435 if (ctl_perm(table, op))
436 return -EPERM;
438 if (table->strategy) {
439 rc = table->strategy(table, name, nlen, oldval, oldlenp,
440 newval, newlen, context);
441 if (rc < 0)
442 return rc;
443 if (rc > 0)
444 return 0;
447 /* If there is no strategy routine, or if the strategy returns
448 * zero, proceed with automatic r/w */
449 if (table->data && table->maxlen) {
450 if (oldval && oldlenp) {
451 get_user(len, oldlenp);
452 if (len) {
453 if (len > table->maxlen)
454 len = table->maxlen;
455 if(copy_to_user(oldval, table->data, len))
456 return -EFAULT;
457 if(put_user(len, oldlenp))
458 return -EFAULT;
461 if (newval && newlen) {
462 len = newlen;
463 if (len > table->maxlen)
464 len = table->maxlen;
465 if(copy_from_user(table->data, newval, len))
466 return -EFAULT;
469 return 0;
472 struct ctl_table_header *register_sysctl_table(ctl_table * table,
473 int insert_at_head)
475 struct ctl_table_header *tmp;
476 tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
477 if (!tmp)
478 return 0;
479 tmp->ctl_table = table;
480 INIT_LIST_HEAD(&tmp->ctl_entry);
481 if (insert_at_head)
482 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
483 else
484 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
485 #ifdef CONFIG_PROC_FS
486 register_proc_table(table, proc_sys_root);
487 #endif
488 return tmp;
492 * Unlink and free a ctl_table.
494 void unregister_sysctl_table(struct ctl_table_header * header)
496 list_del(&header->ctl_entry);
497 #ifdef CONFIG_PROC_FS
498 unregister_proc_table(header->ctl_table, proc_sys_root);
499 #endif
500 kfree(header);
504 * /proc/sys support
507 #ifdef CONFIG_PROC_FS
509 /* Scan the sysctl entries in table and add them all into /proc */
510 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
512 struct proc_dir_entry *de;
513 int len;
514 mode_t mode;
516 for (; table->ctl_name; table++) {
517 /* Can't do anything without a proc name. */
518 if (!table->procname)
519 continue;
520 /* Maybe we can't do anything with it... */
521 if (!table->proc_handler && !table->child) {
522 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
523 table->procname);
524 continue;
527 len = strlen(table->procname);
528 mode = table->mode;
530 de = NULL;
531 if (table->proc_handler)
532 mode |= S_IFREG;
533 else {
534 mode |= S_IFDIR;
535 for (de = root->subdir; de; de = de->next) {
536 if (proc_match(len, table->procname, de))
537 break;
539 /* If the subdir exists already, de is non-NULL */
542 if (!de) {
543 de = create_proc_entry(table->procname, mode, root);
544 if (!de)
545 continue;
546 de->data = (void *) table;
547 if (table->proc_handler) {
548 de->proc_fops = &proc_sys_file_operations;
549 de->proc_iops = &proc_sys_inode_operations;
552 table->de = de;
553 if (de->mode & S_IFDIR)
554 register_proc_table(table->child, de);
559 * Unregister a /proc sysctl table and any subdirectories.
561 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
563 struct proc_dir_entry *de;
564 for (; table->ctl_name; table++) {
565 if (!(de = table->de))
566 continue;
567 if (de->mode & S_IFDIR) {
568 if (!table->child) {
569 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
570 continue;
572 unregister_proc_table(table->child, de);
574 /* Don't unregister directories which still have entries.. */
575 if (de->subdir)
576 continue;
579 /* Don't unregister proc entries that are still being used.. */
580 if (atomic_read(&de->count))
581 continue;
583 table->de = NULL;
584 remove_proc_entry(table->procname, root);
588 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
589 size_t count, loff_t *ppos)
591 int op;
592 struct proc_dir_entry *de;
593 struct ctl_table *table;
594 size_t res;
595 ssize_t error;
597 de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
598 if (!de || !de->data)
599 return -ENOTDIR;
600 table = (struct ctl_table *) de->data;
601 if (!table || !table->proc_handler)
602 return -ENOTDIR;
603 op = (write ? 002 : 004);
604 if (ctl_perm(table, op))
605 return -EPERM;
607 res = count;
610 * FIXME: we need to pass on ppos to the handler.
613 error = (*table->proc_handler) (table, write, file, buf, &res);
614 if (error)
615 return error;
616 return res;
619 static ssize_t proc_readsys(struct file * file, char * buf,
620 size_t count, loff_t *ppos)
622 return do_rw_proc(0, file, buf, count, ppos);
625 static ssize_t proc_writesys(struct file * file, const char * buf,
626 size_t count, loff_t *ppos)
628 return do_rw_proc(1, file, (char *) buf, count, ppos);
631 static int proc_sys_permission(struct inode *inode, int op)
633 return test_perm(inode->i_mode, op);
636 int proc_dostring(ctl_table *table, int write, struct file *filp,
637 void *buffer, size_t *lenp)
639 int len;
640 char *p, c;
642 if (!table->data || !table->maxlen || !*lenp ||
643 (filp->f_pos && !write)) {
644 *lenp = 0;
645 return 0;
648 if (write) {
649 len = 0;
650 p = buffer;
651 while (len < *lenp) {
652 if(get_user(c, p++))
653 return -EFAULT;
654 if (c == 0 || c == '\n')
655 break;
656 len++;
658 if (len >= table->maxlen)
659 len = table->maxlen-1;
660 if(copy_from_user(table->data, buffer, len))
661 return -EFAULT;
662 ((char *) table->data)[len] = 0;
663 filp->f_pos += *lenp;
664 } else {
665 len = strlen(table->data);
666 if (len > table->maxlen)
667 len = table->maxlen;
668 if (len > *lenp)
669 len = *lenp;
670 if (len)
671 if(copy_to_user(buffer, table->data, len))
672 return -EFAULT;
673 if (len < *lenp) {
674 if(put_user('\n', ((char *) buffer) + len))
675 return -EFAULT;
676 len++;
678 *lenp = len;
679 filp->f_pos += len;
681 return 0;
685 * Special case of dostring for the UTS structure. This has locks
686 * to observe. Should this be in kernel/sys.c ????
689 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
690 void *buffer, size_t *lenp)
692 int r;
694 if (!write) {
695 down_read(&uts_sem);
696 r=proc_dostring(table,0,filp,buffer,lenp);
697 up_read(&uts_sem);
698 } else {
699 down_write(&uts_sem);
700 r=proc_dostring(table,1,filp,buffer,lenp);
701 up_write(&uts_sem);
703 return r;
706 #define OP_SET 0
707 #define OP_AND 1
708 #define OP_OR 2
709 #define OP_MAX 3
710 #define OP_MIN 4
712 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
713 void *buffer, size_t *lenp, int conv, int op)
715 int *i, vleft, first=1, len, left, neg, val;
716 #define TMPBUFLEN 20
717 char buf[TMPBUFLEN], *p;
719 if (!table->data || !table->maxlen || !*lenp ||
720 (filp->f_pos && !write)) {
721 *lenp = 0;
722 return 0;
725 i = (int *) table->data;
726 vleft = table->maxlen / sizeof(int);
727 left = *lenp;
729 for (; left && vleft--; i++, first=0) {
730 if (write) {
731 while (left) {
732 char c;
733 if(get_user(c,(char *) buffer))
734 return -EFAULT;
735 if (!isspace(c))
736 break;
737 left--;
738 ((char *) buffer)++;
740 if (!left)
741 break;
742 neg = 0;
743 len = left;
744 if (len > TMPBUFLEN-1)
745 len = TMPBUFLEN-1;
746 if(copy_from_user(buf, buffer, len))
747 return -EFAULT;
748 buf[len] = 0;
749 p = buf;
750 if (*p == '-' && left > 1) {
751 neg = 1;
752 left--, p++;
754 if (*p < '0' || *p > '9')
755 break;
756 val = simple_strtoul(p, &p, 0) * conv;
757 len = p-buf;
758 if ((len < left) && *p && !isspace(*p))
759 break;
760 if (neg)
761 val = -val;
762 buffer += len;
763 left -= len;
764 switch(op) {
765 case OP_SET: *i = val; break;
766 case OP_AND: *i &= val; break;
767 case OP_OR: *i |= val; break;
768 case OP_MAX: if(*i < val)
769 *i = val;
770 break;
771 case OP_MIN: if(*i > val)
772 *i = val;
773 break;
775 } else {
776 p = buf;
777 if (!first)
778 *p++ = '\t';
779 sprintf(p, "%d", (*i) / conv);
780 len = strlen(buf);
781 if (len > left)
782 len = left;
783 if(copy_to_user(buffer, buf, len))
784 return -EFAULT;
785 left -= len;
786 buffer += len;
790 if (!write && !first && left) {
791 if(put_user('\n', (char *) buffer))
792 return -EFAULT;
793 left--, buffer++;
795 if (write) {
796 p = (char *) buffer;
797 while (left) {
798 char c;
799 if(get_user(c, p++))
800 return -EFAULT;
801 if (!isspace(c))
802 break;
803 left--;
806 if (write && first)
807 return -EINVAL;
808 *lenp -= left;
809 filp->f_pos += *lenp;
810 return 0;
813 int proc_dointvec(ctl_table *table, int write, struct file *filp,
814 void *buffer, size_t *lenp)
816 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
820 * init may raise the set.
823 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
824 void *buffer, size_t *lenp)
826 if (!capable(CAP_SYS_MODULE)) {
827 return -EPERM;
829 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
830 (current->pid == 1) ? OP_SET : OP_AND);
833 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
834 void *buffer, size_t *lenp)
836 int *i, *min, *max, vleft, first=1, len, left, neg, val;
837 #define TMPBUFLEN 20
838 char buf[TMPBUFLEN], *p;
840 if (!table->data || !table->maxlen || !*lenp ||
841 (filp->f_pos && !write)) {
842 *lenp = 0;
843 return 0;
846 i = (int *) table->data;
847 min = (int *) table->extra1;
848 max = (int *) table->extra2;
849 vleft = table->maxlen / sizeof(int);
850 left = *lenp;
852 for (; left && vleft--; i++, first=0) {
853 if (write) {
854 while (left) {
855 char c;
856 if(get_user(c, (char *) buffer))
857 return -EFAULT;
858 if (!isspace(c))
859 break;
860 left--;
861 ((char *) buffer)++;
863 if (!left)
864 break;
865 neg = 0;
866 len = left;
867 if (len > TMPBUFLEN-1)
868 len = TMPBUFLEN-1;
869 if(copy_from_user(buf, buffer, len))
870 return -EFAULT;
871 buf[len] = 0;
872 p = buf;
873 if (*p == '-' && left > 1) {
874 neg = 1;
875 left--, p++;
877 if (*p < '0' || *p > '9')
878 break;
879 val = simple_strtoul(p, &p, 0);
880 len = p-buf;
881 if ((len < left) && *p && !isspace(*p))
882 break;
883 if (neg)
884 val = -val;
885 buffer += len;
886 left -= len;
888 if (min && val < *min++)
889 continue;
890 if (max && val > *max++)
891 continue;
892 *i = val;
893 } else {
894 p = buf;
895 if (!first)
896 *p++ = '\t';
897 sprintf(p, "%d", *i);
898 len = strlen(buf);
899 if (len > left)
900 len = left;
901 if(copy_to_user(buffer, buf, len))
902 return -EFAULT;
903 left -= len;
904 buffer += len;
908 if (!write && !first && left) {
909 if(put_user('\n', (char *) buffer))
910 return -EFAULT;
911 left--, buffer++;
913 if (write) {
914 p = (char *) buffer;
915 while (left) {
916 char c;
917 if(get_user(c, p++))
918 return -EFAULT;
919 if (!isspace(c))
920 break;
921 left--;
924 if (write && first)
925 return -EINVAL;
926 *lenp -= left;
927 filp->f_pos += *lenp;
928 return 0;
932 * an unsigned long function version
935 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
936 struct file *filp,
937 void *buffer, size_t *lenp,
938 unsigned long convmul,
939 unsigned long convdiv)
941 #define TMPBUFLEN 20
942 unsigned long *i, *min, *max, val;
943 int vleft, first=1, len, left, neg;
944 char buf[TMPBUFLEN], *p;
946 if (!table->data || !table->maxlen || !*lenp ||
947 (filp->f_pos && !write)) {
948 *lenp = 0;
949 return 0;
952 i = (unsigned long *) table->data;
953 min = (unsigned long *) table->extra1;
954 max = (unsigned long *) table->extra2;
955 vleft = table->maxlen / sizeof(unsigned long);
956 left = *lenp;
958 for (; left && vleft--; i++, first=0) {
959 if (write) {
960 while (left) {
961 char c;
962 if(get_user(c, (char *) buffer))
963 return -EFAULT;
964 if (!isspace(c))
965 break;
966 left--;
967 ((char *) buffer)++;
969 if (!left)
970 break;
971 neg = 0;
972 len = left;
973 if (len > TMPBUFLEN-1)
974 len = TMPBUFLEN-1;
975 if(copy_from_user(buf, buffer, len))
976 return -EFAULT;
977 buf[len] = 0;
978 p = buf;
979 if (*p == '-' && left > 1) {
980 neg = 1;
981 left--, p++;
983 if (*p < '0' || *p > '9')
984 break;
985 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
986 len = p-buf;
987 if ((len < left) && *p && !isspace(*p))
988 break;
989 if (neg)
990 val = -val;
991 buffer += len;
992 left -= len;
994 if(neg)
995 continue;
996 if (min && val < *min++)
997 continue;
998 if (max && val > *max++)
999 continue;
1000 *i = val;
1001 } else {
1002 p = buf;
1003 if (!first)
1004 *p++ = '\t';
1005 sprintf(p, "%lu", convdiv * (*i) / convmul);
1006 len = strlen(buf);
1007 if (len > left)
1008 len = left;
1009 if(copy_to_user(buffer, buf, len))
1010 return -EFAULT;
1011 left -= len;
1012 buffer += len;
1016 if (!write && !first && left) {
1017 if(put_user('\n', (char *) buffer))
1018 return -EFAULT;
1019 left--, buffer++;
1021 if (write) {
1022 p = (char *) buffer;
1023 while (left) {
1024 char c;
1025 if(get_user(c, p++))
1026 return -EFAULT;
1027 if (!isspace(c))
1028 break;
1029 left--;
1032 if (write && first)
1033 return -EINVAL;
1034 *lenp -= left;
1035 filp->f_pos += *lenp;
1036 return 0;
1037 #undef TMPBUFLEN
1040 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1041 void *buffer, size_t *lenp)
1043 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1046 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1047 struct file *filp,
1048 void *buffer, size_t *lenp)
1050 return do_proc_doulongvec_minmax(table, write, filp, buffer,
1051 lenp, HZ, 1000l);
1055 /* Like proc_dointvec, but converts seconds to jiffies */
1056 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1057 void *buffer, size_t *lenp)
1059 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1062 #else /* CONFIG_PROC_FS */
1064 int proc_dostring(ctl_table *table, int write, struct file *filp,
1065 void *buffer, size_t *lenp)
1067 return -ENOSYS;
1070 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1071 void *buffer, size_t *lenp)
1073 return -ENOSYS;
1076 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1077 void *buffer, size_t *lenp)
1079 return -ENOSYS;
1082 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1083 void *buffer, size_t *lenp)
1085 return -ENOSYS;
1088 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1089 void *buffer, size_t *lenp)
1091 return -ENOSYS;
1094 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1095 void *buffer, size_t *lenp)
1097 return -ENOSYS;
1100 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1101 void *buffer, size_t *lenp)
1103 return -ENOSYS;
1106 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1107 struct file *filp,
1108 void *buffer, size_t *lenp)
1110 return -ENOSYS;
1114 #endif /* CONFIG_PROC_FS */
1118 * General sysctl support routines
1121 /* The generic string strategy routine: */
1122 int sysctl_string(ctl_table *table, int *name, int nlen,
1123 void *oldval, size_t *oldlenp,
1124 void *newval, size_t newlen, void **context)
1126 int l, len;
1128 if (!table->data || !table->maxlen)
1129 return -ENOTDIR;
1131 if (oldval && oldlenp) {
1132 if(get_user(len, oldlenp))
1133 return -EFAULT;
1134 if (len) {
1135 l = strlen(table->data);
1136 if (len > l) len = l;
1137 if (len >= table->maxlen)
1138 len = table->maxlen;
1139 if(copy_to_user(oldval, table->data, len))
1140 return -EFAULT;
1141 if(put_user(0, ((char *) oldval) + len))
1142 return -EFAULT;
1143 if(put_user(len, oldlenp))
1144 return -EFAULT;
1147 if (newval && newlen) {
1148 len = newlen;
1149 if (len > table->maxlen)
1150 len = table->maxlen;
1151 if(copy_from_user(table->data, newval, len))
1152 return -EFAULT;
1153 if (len == table->maxlen)
1154 len--;
1155 ((char *) table->data)[len] = 0;
1157 return 0;
1161 * This function makes sure that all of the integers in the vector
1162 * are between the minimum and maximum values given in the arrays
1163 * table->extra1 and table->extra2, respectively.
1165 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1166 void *oldval, size_t *oldlenp,
1167 void *newval, size_t newlen, void **context)
1169 int i, length, *vec, *min, *max;
1171 if (newval && newlen) {
1172 if (newlen % sizeof(int) != 0)
1173 return -EINVAL;
1175 if (!table->extra1 && !table->extra2)
1176 return 0;
1178 if (newlen > table->maxlen)
1179 newlen = table->maxlen;
1180 length = newlen / sizeof(int);
1182 vec = (int *) newval;
1183 min = (int *) table->extra1;
1184 max = (int *) table->extra2;
1186 for (i = 0; i < length; i++) {
1187 int value;
1188 get_user(value, vec + i);
1189 if (min && value < min[i])
1190 return -EINVAL;
1191 if (max && value > max[i])
1192 return -EINVAL;
1195 return 0;
1198 /* Strategy function to convert jiffies to seconds */
1199 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1200 void *oldval, size_t *oldlenp,
1201 void *newval, size_t newlen, void **context)
1203 if (oldval) {
1204 size_t olen;
1205 if (oldlenp) {
1206 if (get_user(olen, oldlenp))
1207 return -EFAULT;
1208 if (olen!=sizeof(int))
1209 return -EINVAL;
1211 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1212 (oldlenp && put_user(sizeof(int),oldlenp)))
1213 return -EFAULT;
1215 if (newval && newlen) {
1216 int new;
1217 if (newlen != sizeof(int))
1218 return -EINVAL;
1219 if (get_user(new, (int *)newval))
1220 return -EFAULT;
1221 *(int *)(table->data) = new*HZ;
1223 return 1;
1227 #else /* CONFIG_SYSCTL */
1230 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1232 return -ENOSYS;
1235 int sysctl_string(ctl_table *table, int *name, int nlen,
1236 void *oldval, size_t *oldlenp,
1237 void *newval, size_t newlen, void **context)
1239 return -ENOSYS;
1242 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1243 void *oldval, size_t *oldlenp,
1244 void *newval, size_t newlen, void **context)
1246 return -ENOSYS;
1249 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1250 void *oldval, size_t *oldlenp,
1251 void *newval, size_t newlen, void **context)
1253 return -ENOSYS;
1256 int proc_dostring(ctl_table *table, int write, struct file *filp,
1257 void *buffer, size_t *lenp)
1259 return -ENOSYS;
1262 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1263 void *buffer, size_t *lenp)
1265 return -ENOSYS;
1268 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1269 void *buffer, size_t *lenp)
1271 return -ENOSYS;
1274 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1275 void *buffer, size_t *lenp)
1277 return -ENOSYS;
1280 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1281 void *buffer, size_t *lenp)
1283 return -ENOSYS;
1286 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1287 void *buffer, size_t *lenp)
1289 return -ENOSYS;
1292 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1293 struct file *filp,
1294 void *buffer, size_t *lenp)
1296 return -ENOSYS;
1299 struct ctl_table_header * register_sysctl_table(ctl_table * table,
1300 int insert_at_head)
1302 return 0;
1305 void unregister_sysctl_table(struct ctl_table_header * table)
1309 #endif /* CONFIG_SYSCTL */