1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <linux/config.h>
22#include <linux/mm.h>
23#include <linux/slab.h>
24#include <linux/sysctl.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>
33#include <linux/writeback.h>
34
35#include <asm/uaccess.h>
36
37#ifdef CONFIG_ROOT_NFS
38#include <linux/nfs_fs.h>
39#endif
40
41#if defined(CONFIG_SYSCTL)
42
43
44extern int panic_timeout;
45extern int C_A_D;
46extern int sysctl_overcommit_memory;
47extern int sysctl_overcommit_ratio;
48extern int max_threads;
49extern atomic_t nr_queued_signals;
50extern int max_queued_signals;
51extern int sysrq_enabled;
52extern int core_uses_pid;
53extern int cad_pid;
54extern int pid_max;
55
56
57static int maxolduid = 65535;
58static int minolduid;
59
60#ifdef CONFIG_KMOD
61extern char modprobe_path[];
62#endif
63#ifdef CONFIG_HOTPLUG
64extern char hotplug_path[];
65#endif
66#ifdef CONFIG_CHR_DEV_SG
67extern int sg_big_buff;
68#endif
69#ifdef CONFIG_SYSVIPC
70extern size_t shm_ctlmax;
71extern size_t shm_ctlall;
72extern int shm_ctlmni;
73extern int msg_ctlmax;
74extern int msg_ctlmnb;
75extern int msg_ctlmni;
76extern int sem_ctls[];
77#endif
78
79#ifdef __sparc__
80extern char reboot_command [];
81extern int stop_a_enabled;
82#endif
83
84#ifdef CONFIG_ARCH_S390
85#ifdef CONFIG_MATHEMU
86extern int sysctl_ieee_emulation_warnings;
87#endif
88extern int sysctl_userprocess_debug;
89#endif
90
91#ifdef CONFIG_PPC32
92extern unsigned long zero_paged_on, powersave_nap;
93int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
94 void *buffer, size_t *lenp);
95#endif
96
97#ifdef CONFIG_BSD_PROCESS_ACCT
98extern int acct_parm[];
99#endif
100
101#ifdef CONFIG_HUGETLB_PAGE
102extern int htlbpage_max;
103extern int set_hugetlb_mem_size(int);
104#endif
105
106static int parse_table(int *, int, void *, size_t *, void *, size_t,
107 ctl_table *, void **);
108static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
109 void *buffer, size_t *lenp);
110
111static ctl_table root_table[];
112static struct ctl_table_header root_table_header =
113 { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
114
115static ctl_table kern_table[];
116static ctl_table vm_table[];
117#ifdef CONFIG_NET
118extern ctl_table net_table[];
119#endif
120static ctl_table proc_table[];
121static ctl_table fs_table[];
122static ctl_table debug_table[];
123static ctl_table dev_table[];
124extern ctl_table random_table[];
125
126
127
128#ifdef CONFIG_PROC_FS
129
130static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
131static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
132static int proc_sys_permission(struct inode *, int);
133
134struct file_operations proc_sys_file_operations = {
135 .read = proc_readsys,
136 .write = proc_writesys,
137};
138
139static struct inode_operations proc_sys_inode_operations = {
140 .permission = proc_sys_permission,
141};
142
143extern struct proc_dir_entry *proc_sys_root;
144
145static void register_proc_table(ctl_table *, struct proc_dir_entry *);
146static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
147#endif
148
149
150
151static ctl_table root_table[] = {
152 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
153 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
154#ifdef CONFIG_NET
155 {CTL_NET, "net", NULL, 0, 0555, net_table},
156#endif
157 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
158 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
159 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
160 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
161 {0}
162};
163
164static ctl_table kern_table[] = {
165 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
166 0444, NULL, &proc_doutsstring, &sysctl_string},
167 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
168 0444, NULL, &proc_doutsstring, &sysctl_string},
169 {KERN_VERSION, "version", system_utsname.version, 64,
170 0444, NULL, &proc_doutsstring, &sysctl_string},
171 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
172 0644, NULL, &proc_doutsstring, &sysctl_string},
173 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
174 0644, NULL, &proc_doutsstring, &sysctl_string},
175 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
176 0644, NULL, &proc_dointvec},
177 {KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
178 0644, NULL, &proc_dointvec},
179 {KERN_TAINTED, "tainted", &tainted, sizeof(int),
180 0644, NULL, &proc_dointvec},
181 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
182 0600, NULL, &proc_dointvec_bset},
183#ifdef CONFIG_BLK_DEV_INITRD
184 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
185 0644, NULL, &proc_dointvec},
186#endif
187#ifdef __sparc__
188 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
189 256, 0644, NULL, &proc_dostring, &sysctl_string },
190 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
191 0644, NULL, &proc_dointvec},
192#endif
193#ifdef CONFIG_PPC32
194 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
195 0644, NULL, &proc_dointvec},
196 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
197 0644, NULL, &proc_dointvec},
198 {KERN_PPC_L2CR, "l2cr", NULL, 0,
199 0644, NULL, &proc_dol2crvec},
200#endif
201 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
202 0644, NULL, &proc_dointvec},
203 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
204 0644, NULL, &proc_dointvec},
205#ifdef CONFIG_KMOD
206 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
207 0644, NULL, &proc_dostring, &sysctl_string },
208#endif
209#ifdef CONFIG_HOTPLUG
210 {KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
211 0644, NULL, &proc_dostring, &sysctl_string },
212#endif
213#ifdef CONFIG_CHR_DEV_SG
214 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
215 0444, NULL, &proc_dointvec},
216#endif
217#ifdef CONFIG_BSD_PROCESS_ACCT
218 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
219 0644, NULL, &proc_dointvec},
220#endif
221 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
222 0444, NULL, &proc_dointvec},
223 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
224 0644, NULL, &proc_dointvec},
225#ifdef CONFIG_SYSVIPC
226 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
227 0644, NULL, &proc_doulongvec_minmax},
228 {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (size_t),
229 0644, NULL, &proc_doulongvec_minmax},
230 {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
231 0644, NULL, &proc_dointvec},
232 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
233 0644, NULL, &proc_dointvec},
234 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
235 0644, NULL, &proc_dointvec},
236 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
237 0644, NULL, &proc_dointvec},
238 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
239 0644, NULL, &proc_dointvec},
240#endif
241#ifdef CONFIG_MAGIC_SYSRQ
242 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
243 0644, NULL, &proc_dointvec},
244#endif
245 {KERN_CADPID, "cad_pid", &cad_pid, sizeof (int),
246 0600, NULL, &proc_dointvec},
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},
256#ifdef CONFIG_ARCH_S390
257#ifdef CONFIG_MATHEMU
258 {KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings",
259 &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec},
260#endif
261 {KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug",
262 &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec},
263#endif
264 {KERN_PIDMAX, "pid_max", &pid_max, sizeof (int),
265 0600, NULL, &proc_dointvec},
266 {0}
267};
268
269
270
271static int zero = 0;
272static int one = 1;
273static int one_hundred = 100;
274
275
276static ctl_table vm_table[] = {
277 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
278 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
279 {VM_OVERCOMMIT_RATIO, "overcommit_ratio",
280 &sysctl_overcommit_ratio, sizeof(sysctl_overcommit_ratio), 0644,
281 NULL, &proc_dointvec},
282 {VM_PAGE_CLUSTER, "page-cluster",
283 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
284 {VM_DIRTY_BACKGROUND, "dirty_background_ratio",
285 &dirty_background_ratio, sizeof(dirty_background_ratio),
286 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
287 &zero, &one_hundred },
288 {VM_DIRTY_ASYNC, "dirty_async_ratio", &dirty_async_ratio,
289 sizeof(dirty_async_ratio), 0644, NULL, &proc_dointvec_minmax,
290 &sysctl_intvec, NULL, &zero, &one_hundred },
291 {VM_DIRTY_WB_CS, "dirty_writeback_centisecs",
292 &dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644,
293 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
294
295
296
297
298
299
300
301
302
303
304
305
306 &one , NULL},
307 {VM_DIRTY_EXPIRE_CS, "dirty_expire_centisecs",
308 &dirty_expire_centisecs, sizeof(dirty_expire_centisecs), 0644,
309 NULL, &proc_dointvec},
310 { VM_NR_PDFLUSH_THREADS, "nr_pdflush_threads",
311 &nr_pdflush_threads, sizeof nr_pdflush_threads,
312 0444 , NULL, &proc_dointvec},
313#ifdef CONFIG_HUGETLB_PAGE
314 {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL,
315 &proc_dointvec},
316#endif
317 {0}
318};
319
320static ctl_table proc_table[] = {
321 {0}
322};
323
324static ctl_table fs_table[] = {
325 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
326 0444, NULL, &proc_dointvec},
327 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
328 0444, NULL, &proc_dointvec},
329 {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
330 0444, NULL, &proc_dointvec},
331 {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
332 0644, NULL, &proc_dointvec},
333 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
334 0444, NULL, &proc_dointvec},
335 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
336 &proc_dointvec_minmax, &sysctl_intvec, NULL,
337 &minolduid, &maxolduid},
338 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
339 &proc_dointvec_minmax, &sysctl_intvec, NULL,
340 &minolduid, &maxolduid},
341 {FS_LEASES, "leases-enable", &leases_enable, sizeof(int),
342 0644, NULL, &proc_dointvec},
343 {FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable,
344 sizeof(int), 0644, NULL, &proc_dointvec},
345 {FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int),
346 0644, NULL, &proc_dointvec},
347 {0}
348};
349
350static ctl_table debug_table[] = {
351 {0}
352};
353
354static ctl_table dev_table[] = {
355 {0}
356};
357
358extern void init_irq_proc (void);
359
360void __init sysctl_init(void)
361{
362#ifdef CONFIG_PROC_FS
363 register_proc_table(root_table, proc_sys_root);
364 init_irq_proc();
365#endif
366}
367
368int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
369 void *newval, size_t newlen)
370{
371 struct list_head *tmp;
372
373 if (nlen <= 0 || nlen >= CTL_MAXNAME)
374 return -ENOTDIR;
375 if (oldval) {
376 int old_len;
377 if (!oldlenp || get_user(old_len, oldlenp))
378 return -EFAULT;
379 }
380 tmp = &root_table_header.ctl_entry;
381 do {
382 struct ctl_table_header *head =
383 list_entry(tmp, struct ctl_table_header, ctl_entry);
384 void *context = NULL;
385 int error = parse_table(name, nlen, oldval, oldlenp,
386 newval, newlen, head->ctl_table,
387 &context);
388 if (context)
389 kfree(context);
390 if (error != -ENOTDIR)
391 return error;
392 tmp = tmp->next;
393 } while (tmp != &root_table_header.ctl_entry);
394 return -ENOTDIR;
395}
396
397extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
398{
399 struct __sysctl_args tmp;
400 int error;
401
402 if (copy_from_user(&tmp, args, sizeof(tmp)))
403 return -EFAULT;
404
405 lock_kernel();
406 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
407 tmp.newval, tmp.newlen);
408 unlock_kernel();
409 return error;
410}
411
412
413
414
415
416
417static int test_perm(int mode, int op)
418{
419 if (!current->euid)
420 mode >>= 6;
421 else if (in_egroup_p(0))
422 mode >>= 3;
423 if ((mode & op & 0007) == op)
424 return 0;
425 return -EACCES;
426}
427
428static inline int ctl_perm(ctl_table *table, int op)
429{
430 return test_perm(table->mode, op);
431}
432
433static int parse_table(int *name, int nlen,
434 void *oldval, size_t *oldlenp,
435 void *newval, size_t newlen,
436 ctl_table *table, void **context)
437{
438 int n;
439repeat:
440 if (!nlen)
441 return -ENOTDIR;
442 if (get_user(n, name))
443 return -EFAULT;
444 for ( ; table->ctl_name; table++) {
445 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
446 int error;
447 if (table->child) {
448 if (ctl_perm(table, 001))
449 return -EPERM;
450 if (table->strategy) {
451 error = table->strategy(
452 table, name, nlen,
453 oldval, oldlenp,
454 newval, newlen, context);
455 if (error)
456 return error;
457 }
458 name++;
459 nlen--;
460 table = table->child;
461 goto repeat;
462 }
463 error = do_sysctl_strategy(table, name, nlen,
464 oldval, oldlenp,
465 newval, newlen, context);
466 return error;
467 }
468 }
469 return -ENOTDIR;
470}
471
472
473int do_sysctl_strategy (ctl_table *table,
474 int *name, int nlen,
475 void *oldval, size_t *oldlenp,
476 void *newval, size_t newlen, void **context)
477{
478 int op = 0, rc;
479 size_t len;
480
481 if (oldval)
482 op |= 004;
483 if (newval)
484 op |= 002;
485 if (ctl_perm(table, op))
486 return -EPERM;
487
488 if (table->strategy) {
489 rc = table->strategy(table, name, nlen, oldval, oldlenp,
490 newval, newlen, context);
491 if (rc < 0)
492 return rc;
493 if (rc > 0)
494 return 0;
495 }
496
497
498
499 if (table->data && table->maxlen) {
500 if (oldval && oldlenp) {
501 get_user(len, oldlenp);
502 if (len) {
503 if (len > table->maxlen)
504 len = table->maxlen;
505 if(copy_to_user(oldval, table->data, len))
506 return -EFAULT;
507 if(put_user(len, oldlenp))
508 return -EFAULT;
509 }
510 }
511 if (newval && newlen) {
512 len = newlen;
513 if (len > table->maxlen)
514 len = table->maxlen;
515 if(copy_from_user(table->data, newval, len))
516 return -EFAULT;
517 }
518 }
519 return 0;
520}
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591struct ctl_table_header *register_sysctl_table(ctl_table * table,
592 int insert_at_head)
593{
594 struct ctl_table_header *tmp;
595 tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
596 if (!tmp)
597 return NULL;
598 tmp->ctl_table = table;
599 INIT_LIST_HEAD(&tmp->ctl_entry);
600 if (insert_at_head)
601 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
602 else
603 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
604#ifdef CONFIG_PROC_FS
605 register_proc_table(table, proc_sys_root);
606#endif
607 return tmp;
608}
609
610
611
612
613
614
615
616
617void unregister_sysctl_table(struct ctl_table_header * header)
618{
619 list_del(&header->ctl_entry);
620#ifdef CONFIG_PROC_FS
621 unregister_proc_table(header->ctl_table, proc_sys_root);
622#endif
623 kfree(header);
624}
625
626
627
628
629
630#ifdef CONFIG_PROC_FS
631
632
633static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
634{
635 struct proc_dir_entry *de;
636 int len;
637 mode_t mode;
638
639 for (; table->ctl_name; table++) {
640
641 if (!table->procname)
642 continue;
643
644 if (!table->proc_handler && !table->child) {
645 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
646 table->procname);
647 continue;
648 }
649
650 len = strlen(table->procname);
651 mode = table->mode;
652
653 de = NULL;
654 if (table->proc_handler)
655 mode |= S_IFREG;
656 else {
657 mode |= S_IFDIR;
658 for (de = root->subdir; de; de = de->next) {
659 if (proc_match(len, table->procname, de))
660 break;
661 }
662
663 }
664
665 if (!de) {
666 de = create_proc_entry(table->procname, mode, root);
667 if (!de)
668 continue;
669 de->data = (void *) table;
670 if (table->proc_handler) {
671 de->proc_fops = &proc_sys_file_operations;
672 de->proc_iops = &proc_sys_inode_operations;
673 }
674 }
675 table->de = de;
676 if (de->mode & S_IFDIR)
677 register_proc_table(table->child, de);
678 }
679}
680
681
682
683
684static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
685{
686 struct proc_dir_entry *de;
687 for (; table->ctl_name; table++) {
688 if (!(de = table->de))
689 continue;
690 if (de->mode & S_IFDIR) {
691 if (!table->child) {
692 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
693 continue;
694 }
695 unregister_proc_table(table->child, de);
696
697
698 if (de->subdir)
699 continue;
700 }
701
702
703 if (atomic_read(&de->count))
704 continue;
705
706 table->de = NULL;
707 remove_proc_entry(table->procname, root);
708 }
709}
710
711static ssize_t do_rw_proc(int write, struct file * file, char * buf,
712 size_t count, loff_t *ppos)
713{
714 int op;
715 struct proc_dir_entry *de;
716 struct ctl_table *table;
717 size_t res;
718 ssize_t error;
719
720 de = PDE(file->f_dentry->d_inode);
721 if (!de || !de->data)
722 return -ENOTDIR;
723 table = (struct ctl_table *) de->data;
724 if (!table || !table->proc_handler)
725 return -ENOTDIR;
726 op = (write ? 002 : 004);
727 if (ctl_perm(table, op))
728 return -EPERM;
729
730 res = count;
731
732
733
734
735
736 error = (*table->proc_handler) (table, write, file, buf, &res);
737 if (error)
738 return error;
739 return res;
740}
741
742static ssize_t proc_readsys(struct file * file, char * buf,
743 size_t count, loff_t *ppos)
744{
745 return do_rw_proc(0, file, buf, count, ppos);
746}
747
748static ssize_t proc_writesys(struct file * file, const char * buf,
749 size_t count, loff_t *ppos)
750{
751 return do_rw_proc(1, file, (char *) buf, count, ppos);
752}
753
754static int proc_sys_permission(struct inode *inode, int op)
755{
756 return test_perm(inode->i_mode, op);
757}
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776int proc_dostring(ctl_table *table, int write, struct file *filp,
777 void *buffer, size_t *lenp)
778{
779 size_t len;
780 char *p, c;
781
782 if (!table->data || !table->maxlen || !*lenp ||
783 (filp->f_pos && !write)) {
784 *lenp = 0;
785 return 0;
786 }
787
788 if (write) {
789 len = 0;
790 p = buffer;
791 while (len < *lenp) {
792 if(get_user(c, p++))
793 return -EFAULT;
794 if (c == 0 || c == '\n')
795 break;
796 len++;
797 }
798 if (len >= table->maxlen)
799 len = table->maxlen-1;
800 if(copy_from_user(table->data, buffer, len))
801 return -EFAULT;
802 ((char *) table->data)[len] = 0;
803 filp->f_pos += *lenp;
804 } else {
805 len = strlen(table->data);
806 if (len > table->maxlen)
807 len = table->maxlen;
808 if (len > *lenp)
809 len = *lenp;
810 if (len)
811 if(copy_to_user(buffer, table->data, len))
812 return -EFAULT;
813 if (len < *lenp) {
814 if(put_user('\n', ((char *) buffer) + len))
815 return -EFAULT;
816 len++;
817 }
818 *lenp = len;
819 filp->f_pos += len;
820 }
821 return 0;
822}
823
824
825
826
827
828
829static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
830 void *buffer, size_t *lenp)
831{
832 int r;
833
834 if (!write) {
835 down_read(&uts_sem);
836 r=proc_dostring(table,0,filp,buffer,lenp);
837 up_read(&uts_sem);
838 } else {
839 down_write(&uts_sem);
840 r=proc_dostring(table,1,filp,buffer,lenp);
841 up_write(&uts_sem);
842 }
843 return r;
844}
845
846#define OP_SET 0
847#define OP_AND 1
848#define OP_OR 2
849#define OP_MAX 3
850#define OP_MIN 4
851
852static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
853 void *buffer, size_t *lenp, int conv, int op)
854{
855 int *i, vleft, first=1, neg, val;
856 size_t left, len;
857
858 #define TMPBUFLEN 20
859 char buf[TMPBUFLEN], *p;
860
861 if (!table->data || !table->maxlen || !*lenp ||
862 (filp->f_pos && !write)) {
863 *lenp = 0;
864 return 0;
865 }
866
867 i = (int *) table->data;
868 vleft = table->maxlen / sizeof(int);
869 left = *lenp;
870
871 for (; left && vleft--; i++, first=0) {
872 if (write) {
873 while (left) {
874 char c;
875 if(get_user(c,(char *) buffer))
876 return -EFAULT;
877 if (!isspace(c))
878 break;
879 left--;
880 ((char *) buffer)++;
881 }
882 if (!left)
883 break;
884 neg = 0;
885 len = left;
886 if (len > TMPBUFLEN-1)
887 len = TMPBUFLEN-1;
888 if(copy_from_user(buf, buffer, len))
889 return -EFAULT;
890 buf[len] = 0;
891 p = buf;
892 if (*p == '-' && left > 1) {
893 neg = 1;
894 left--, p++;
895 }
896 if (*p < '0' || *p > '9')
897 break;
898 val = simple_strtoul(p, &p, 0) * conv;
899 len = p-buf;
900 if ((len < left) && *p && !isspace(*p))
901 break;
902 if (neg)
903 val = -val;
904 buffer += len;
905 left -= len;
906#ifdef CONFIG_HUGETLB_PAGE
907 if (i == &htlbpage_max)
908 val = set_hugetlb_mem_size(val);
909#endif
910 switch(op) {
911 case OP_SET: *i = val; break;
912 case OP_AND: *i &= val; break;
913 case OP_OR: *i |= val; break;
914 case OP_MAX: if(*i < val)
915 *i = val;
916 break;
917 case OP_MIN: if(*i > val)
918 *i = val;
919 break;
920 }
921 } else {
922 p = buf;
923 if (!first)
924 *p++ = '\t';
925 sprintf(p, "%d", (*i) / conv);
926 len = strlen(buf);
927 if (len > left)
928 len = left;
929 if(copy_to_user(buffer, buf, len))
930 return -EFAULT;
931 left -= len;
932 buffer += len;
933 }
934 }
935
936 if (!write && !first && left) {
937 if(put_user('\n', (char *) buffer))
938 return -EFAULT;
939 left--, buffer++;
940 }
941 if (write) {
942 p = (char *) buffer;
943 while (left) {
944 char c;
945 if(get_user(c, p++))
946 return -EFAULT;
947 if (!isspace(c))
948 break;
949 left--;
950 }
951 }
952 if (write && first)
953 return -EINVAL;
954 *lenp -= left;
955 filp->f_pos += *lenp;
956 return 0;
957}
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972int proc_dointvec(ctl_table *table, int write, struct file *filp,
973 void *buffer, size_t *lenp)
974{
975 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
976}
977
978
979
980
981
982int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
983 void *buffer, size_t *lenp)
984{
985 if (!capable(CAP_SYS_MODULE)) {
986 return -EPERM;
987 }
988 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
989 (current->pid == 1) ? OP_SET : OP_AND);
990}
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1009 void *buffer, size_t *lenp)
1010{
1011 int *i, *min, *max, vleft, first=1, neg, val;
1012 size_t len, left;
1013 #define TMPBUFLEN 20
1014 char buf[TMPBUFLEN], *p;
1015
1016 if (!table->data || !table->maxlen || !*lenp ||
1017 (filp->f_pos && !write)) {
1018 *lenp = 0;
1019 return 0;
1020 }
1021
1022 i = (int *) table->data;
1023 min = (int *) table->extra1;
1024 max = (int *) table->extra2;
1025 vleft = table->maxlen / sizeof(int);
1026 left = *lenp;
1027
1028 for (; left && vleft--; i++, min++, max++, first=0) {
1029 if (write) {
1030 while (left) {
1031 char c;
1032 if(get_user(c, (char *) buffer))
1033 return -EFAULT;
1034 if (!isspace(c))
1035 break;
1036 left--;
1037 ((char *) buffer)++;
1038 }
1039 if (!left)
1040 break;
1041 neg = 0;
1042 len = left;
1043 if (len > TMPBUFLEN-1)
1044 len = TMPBUFLEN-1;
1045 if(copy_from_user(buf, buffer, len))
1046 return -EFAULT;
1047 buf[len] = 0;
1048 p = buf;
1049 if (*p == '-' && left > 1) {
1050 neg = 1;
1051 left--, p++;
1052 }
1053 if (*p < '0' || *p > '9')
1054 break;
1055 val = simple_strtoul(p, &p, 0);
1056 len = p-buf;
1057 if ((len < left) && *p && !isspace(*p))
1058 break;
1059 if (neg)
1060 val = -val;
1061 buffer += len;
1062 left -= len;
1063
1064 if ((min && val < *min) || (max && val > *max))
1065 continue;
1066 *i = val;
1067 } else {
1068 p = buf;
1069 if (!first)
1070 *p++ = '\t';
1071 sprintf(p, "%d", *i);
1072 len = strlen(buf);
1073 if (len > left)
1074 len = left;
1075 if(copy_to_user(buffer, buf, len))
1076 return -EFAULT;
1077 left -= len;
1078 buffer += len;
1079 }
1080 }
1081
1082 if (!write && !first && left) {
1083 if(put_user('\n', (char *) buffer))
1084 return -EFAULT;
1085 left--, buffer++;
1086 }
1087 if (write) {
1088 p = (char *) buffer;
1089 while (left) {
1090 char c;
1091 if(get_user(c, p++))
1092 return -EFAULT;
1093 if (!isspace(c))
1094 break;
1095 left--;
1096 }
1097 }
1098 if (write && first)
1099 return -EINVAL;
1100 *lenp -= left;
1101 filp->f_pos += *lenp;
1102 return 0;
1103}
1104
1105static int do_proc_doulongvec_minmax(ctl_table *table, int write,
1106 struct file *filp,
1107 void *buffer, size_t *lenp,
1108 unsigned long convmul,
1109 unsigned long convdiv)
1110{
1111#define TMPBUFLEN 20
1112 unsigned long *i, *min, *max, val;
1113 int vleft, first=1, neg;
1114 size_t len, left;
1115 char buf[TMPBUFLEN], *p;
1116
1117 if (!table->data || !table->maxlen || !*lenp ||
1118 (filp->f_pos && !write)) {
1119 *lenp = 0;
1120 return 0;
1121 }
1122
1123 i = (unsigned long *) table->data;
1124 min = (unsigned long *) table->extra1;
1125 max = (unsigned long *) table->extra2;
1126 vleft = table->maxlen / sizeof(unsigned long);
1127 left = *lenp;
1128
1129 for (; left && vleft--; i++, min++, max++, first=0) {
1130 if (write) {
1131 while (left) {
1132 char c;
1133 if(get_user(c, (char *) buffer))
1134 return -EFAULT;
1135 if (!isspace(c))
1136 break;
1137 left--;
1138 ((char *) buffer)++;
1139 }
1140 if (!left)
1141 break;
1142 neg = 0;
1143 len = left;
1144 if (len > TMPBUFLEN-1)
1145 len = TMPBUFLEN-1;
1146 if(copy_from_user(buf, buffer, len))
1147 return -EFAULT;
1148 buf[len] = 0;
1149 p = buf;
1150 if (*p == '-' && left > 1) {
1151 neg = 1;
1152 left--, p++;
1153 }
1154 if (*p < '0' || *p > '9')
1155 break;
1156 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
1157 len = p-buf;
1158 if ((len < left) && *p && !isspace(*p))
1159 break;
1160 if (neg)
1161 val = -val;
1162 buffer += len;
1163 left -= len;
1164
1165 if(neg)
1166 continue;
1167 if ((min && val < *min) || (max && val > *max))
1168 continue;
1169 *i = val;
1170 } else {
1171 p = buf;
1172 if (!first)
1173 *p++ = '\t';
1174 sprintf(p, "%lu", convdiv * (*i) / convmul);
1175 len = strlen(buf);
1176 if (len > left)
1177 len = left;
1178 if(copy_to_user(buffer, buf, len))
1179 return -EFAULT;
1180 left -= len;
1181 buffer += len;
1182 }
1183 }
1184
1185 if (!write && !first && left) {
1186 if(put_user('\n', (char *) buffer))
1187 return -EFAULT;
1188 left--, buffer++;
1189 }
1190 if (write) {
1191 p = (char *) buffer;
1192 while (left) {
1193 char c;
1194 if(get_user(c, p++))
1195 return -EFAULT;
1196 if (!isspace(c))
1197 break;
1198 left--;
1199 }
1200 }
1201 if (write && first)
1202 return -EINVAL;
1203 *lenp -= left;
1204 filp->f_pos += *lenp;
1205 return 0;
1206#undef TMPBUFLEN
1207}
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1226 void *buffer, size_t *lenp)
1227{
1228 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1229}
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1249 struct file *filp,
1250 void *buffer, size_t *lenp)
1251{
1252 return do_proc_doulongvec_minmax(table, write, filp, buffer,
1253 lenp, HZ, 1000l);
1254}
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1273 void *buffer, size_t *lenp)
1274{
1275 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1276}
1277
1278#else
1279
1280int proc_dostring(ctl_table *table, int write, struct file *filp,
1281 void *buffer, size_t *lenp)
1282{
1283 return -ENOSYS;
1284}
1285
1286static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1287 void *buffer, size_t *lenp)
1288{
1289 return -ENOSYS;
1290}
1291
1292int proc_dointvec(ctl_table *table, int write, struct file *filp,
1293 void *buffer, size_t *lenp)
1294{
1295 return -ENOSYS;
1296}
1297
1298int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1299 void *buffer, size_t *lenp)
1300{
1301 return -ENOSYS;
1302}
1303
1304int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1305 void *buffer, size_t *lenp)
1306{
1307 return -ENOSYS;
1308}
1309
1310int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1311 void *buffer, size_t *lenp)
1312{
1313 return -ENOSYS;
1314}
1315
1316int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1317 void *buffer, size_t *lenp)
1318{
1319 return -ENOSYS;
1320}
1321
1322int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1323 struct file *filp,
1324 void *buffer, size_t *lenp)
1325{
1326 return -ENOSYS;
1327}
1328
1329
1330#endif
1331
1332
1333
1334
1335
1336
1337
1338int sysctl_string(ctl_table *table, int *name, int nlen,
1339 void *oldval, size_t *oldlenp,
1340 void *newval, size_t newlen, void **context)
1341{
1342 size_t l, len;
1343
1344 if (!table->data || !table->maxlen)
1345 return -ENOTDIR;
1346
1347 if (oldval && oldlenp) {
1348 if(get_user(len, oldlenp))
1349 return -EFAULT;
1350 if (len) {
1351 l = strlen(table->data);
1352 if (len > l) len = l;
1353 if (len >= table->maxlen)
1354 len = table->maxlen;
1355 if(copy_to_user(oldval, table->data, len))
1356 return -EFAULT;
1357 if(put_user(0, ((char *) oldval) + len))
1358 return -EFAULT;
1359 if(put_user(len, oldlenp))
1360 return -EFAULT;
1361 }
1362 }
1363 if (newval && newlen) {
1364 len = newlen;
1365 if (len > table->maxlen)
1366 len = table->maxlen;
1367 if(copy_from_user(table->data, newval, len))
1368 return -EFAULT;
1369 if (len == table->maxlen)
1370 len--;
1371 ((char *) table->data)[len] = 0;
1372 }
1373 return 0;
1374}
1375
1376
1377
1378
1379
1380
1381int sysctl_intvec(ctl_table *table, int *name, int nlen,
1382 void *oldval, size_t *oldlenp,
1383 void *newval, size_t newlen, void **context)
1384{
1385 int i, *vec, *min, *max;
1386 size_t length;
1387
1388 if (newval && newlen) {
1389 if (newlen % sizeof(int) != 0)
1390 return -EINVAL;
1391
1392 if (!table->extra1 && !table->extra2)
1393 return 0;
1394
1395 if (newlen > table->maxlen)
1396 newlen = table->maxlen;
1397 length = newlen / sizeof(int);
1398
1399 vec = (int *) newval;
1400 min = (int *) table->extra1;
1401 max = (int *) table->extra2;
1402
1403 for (i = 0; i < length; i++) {
1404 int value;
1405 get_user(value, vec + i);
1406 if (min && value < min[i])
1407 return -EINVAL;
1408 if (max && value > max[i])
1409 return -EINVAL;
1410 }
1411 }
1412 return 0;
1413}
1414
1415
1416int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1417 void *oldval, size_t *oldlenp,
1418 void *newval, size_t newlen, void **context)
1419{
1420 if (oldval) {
1421 size_t olen;
1422 if (oldlenp) {
1423 if (get_user(olen, oldlenp))
1424 return -EFAULT;
1425 if (olen!=sizeof(int))
1426 return -EINVAL;
1427 }
1428 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1429 (oldlenp && put_user(sizeof(int),oldlenp)))
1430 return -EFAULT;
1431 }
1432 if (newval && newlen) {
1433 int new;
1434 if (newlen != sizeof(int))
1435 return -EINVAL;
1436 if (get_user(new, (int *)newval))
1437 return -EFAULT;
1438 *(int *)(table->data) = new*HZ;
1439 }
1440 return 1;
1441}
1442
1443
1444#else
1445
1446
1447extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1448{
1449 return -ENOSYS;
1450}
1451
1452int sysctl_string(ctl_table *table, int *name, int nlen,
1453 void *oldval, size_t *oldlenp,
1454 void *newval, size_t newlen, void **context)
1455{
1456 return -ENOSYS;
1457}
1458
1459int sysctl_intvec(ctl_table *table, int *name, int nlen,
1460 void *oldval, size_t *oldlenp,
1461 void *newval, size_t newlen, void **context)
1462{
1463 return -ENOSYS;
1464}
1465
1466int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1467 void *oldval, size_t *oldlenp,
1468 void *newval, size_t newlen, void **context)
1469{
1470 return -ENOSYS;
1471}
1472
1473int proc_dostring(ctl_table *table, int write, struct file *filp,
1474 void *buffer, size_t *lenp)
1475{
1476 return -ENOSYS;
1477}
1478
1479int proc_dointvec(ctl_table *table, int write, struct file *filp,
1480 void *buffer, size_t *lenp)
1481{
1482 return -ENOSYS;
1483}
1484
1485int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1486 void *buffer, size_t *lenp)
1487{
1488 return -ENOSYS;
1489}
1490
1491int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1492 void *buffer, size_t *lenp)
1493{
1494 return -ENOSYS;
1495}
1496
1497int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1498 void *buffer, size_t *lenp)
1499{
1500 return -ENOSYS;
1501}
1502
1503int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1504 void *buffer, size_t *lenp)
1505{
1506 return -ENOSYS;
1507}
1508
1509int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1510 struct file *filp,
1511 void *buffer, size_t *lenp)
1512{
1513 return -ENOSYS;
1514}
1515
1516struct ctl_table_header * register_sysctl_table(ctl_table * table,
1517 int insert_at_head)
1518{
1519 return 0;
1520}
1521
1522void unregister_sysctl_table(struct ctl_table_header * table)
1523{
1524}
1525
1526#endif
1527