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/slab.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>
33#include <linux/swap.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 bdf_prm[], bdflush_min[], bdflush_max[];
47extern int sysctl_overcommit_memory;
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 core_setuid_ok;
54extern char core_pattern[];
55extern int cad_pid;
56extern int laptop_mode;
57extern int block_dump;
58
59
60static int maxolduid = 65535;
61static int minolduid;
62
63#ifdef CONFIG_KMOD
64extern char modprobe_path[];
65#endif
66#ifdef CONFIG_HOTPLUG
67extern char hotplug_path[];
68#endif
69#ifdef CONFIG_CHR_DEV_SG
70extern int sg_big_buff;
71#endif
72#ifdef CONFIG_SYSVIPC
73extern size_t shm_ctlmax;
74extern size_t shm_ctlall;
75extern int shm_ctlmni;
76extern int msg_ctlmax;
77extern int msg_ctlmnb;
78extern int msg_ctlmni;
79extern int sem_ctls[];
80#endif
81
82extern int exception_trace;
83
84#ifdef __sparc__
85extern char reboot_command [];
86extern int stop_a_enabled;
87extern int scons_pwroff;
88#endif
89
90#ifdef CONFIG_ARCH_S390
91#ifdef CONFIG_MATHEMU
92extern int sysctl_ieee_emulation_warnings;
93#endif
94extern int sysctl_userprocess_debug;
95#endif
96
97#ifdef CONFIG_PPC32
98extern unsigned long zero_paged_on, powersave_nap;
99int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
100 void *buffer, size_t *lenp);
101int proc_dol3crvec(ctl_table *table, int write, struct file *filp,
102 void *buffer, size_t *lenp);
103#endif
104
105#ifdef CONFIG_BSD_PROCESS_ACCT
106extern int acct_parm[];
107#endif
108
109extern int pgt_cache_water[];
110
111static int parse_table(int *, int, void *, size_t *, void *, size_t,
112 ctl_table *, void **);
113static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
114 void *buffer, size_t *lenp);
115
116static ctl_table root_table[];
117static struct ctl_table_header root_table_header =
118 { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
119
120static ctl_table kern_table[];
121static ctl_table vm_table[];
122#ifdef CONFIG_NET
123extern ctl_table net_table[];
124#endif
125static ctl_table proc_table[];
126static ctl_table fs_table[];
127static ctl_table debug_table[];
128static ctl_table dev_table[];
129extern ctl_table random_table[];
130
131
132
133#ifdef CONFIG_PROC_FS
134
135static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
136static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
137static int proc_sys_permission(struct inode *, int);
138
139struct file_operations proc_sys_file_operations = {
140 read: proc_readsys,
141 write: proc_writesys,
142};
143
144static struct inode_operations proc_sys_inode_operations = {
145 permission: proc_sys_permission,
146};
147
148extern struct proc_dir_entry *proc_sys_root;
149
150static void register_proc_table(ctl_table *, struct proc_dir_entry *);
151static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
152#endif
153
154
155
156static ctl_table root_table[] = {
157 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
158 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
159#ifdef CONFIG_NET
160 {CTL_NET, "net", NULL, 0, 0555, net_table},
161#endif
162 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
163 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
164 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
165 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
166 {0}
167};
168
169static ctl_table kern_table[] = {
170 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
171 0444, NULL, &proc_doutsstring, &sysctl_string},
172 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
173 0444, NULL, &proc_doutsstring, &sysctl_string},
174 {KERN_VERSION, "version", system_utsname.version, 64,
175 0444, NULL, &proc_doutsstring, &sysctl_string},
176 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
177 0644, NULL, &proc_doutsstring, &sysctl_string},
178 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
179 0644, NULL, &proc_doutsstring, &sysctl_string},
180 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
181 0644, NULL, &proc_dointvec},
182 {KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
183 0644, NULL, &proc_dointvec},
184 {KERN_CORE_SETUID, "core_setuid_ok", &core_setuid_ok, sizeof(int),
185 0644, NULL, &proc_dointvec},
186 {KERN_CORE_PATTERN, "core_pattern", core_pattern, 64,
187 0644, NULL, &proc_dostring, &sysctl_string},
188 {KERN_TAINTED, "tainted", &tainted, sizeof(int),
189 0644, NULL, &proc_dointvec},
190 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
191 0600, NULL, &proc_dointvec_bset},
192#ifdef CONFIG_BLK_DEV_INITRD
193 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
194 0644, NULL, &proc_dointvec},
195#endif
196#ifdef __sparc__
197 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
198 256, 0644, NULL, &proc_dostring, &sysctl_string },
199 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
200 0644, NULL, &proc_dointvec},
201 {KERN_SPARC_SCONS_PWROFF, "scons-poweroff", &scons_pwroff, sizeof (int),
202 0644, NULL, &proc_dointvec},
203#endif
204#ifdef CONFIG_PPC32
205 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
206 0644, NULL, &proc_dointvec},
207 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
208 0644, NULL, &proc_dointvec},
209 {KERN_PPC_L2CR, "l2cr", NULL, 0,
210 0644, NULL, &proc_dol2crvec},
211 {KERN_PPC_L3CR, "l3cr", NULL, 0,
212 0644, NULL, &proc_dol3crvec},
213#endif
214 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
215 0644, NULL, &proc_dointvec},
216 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
217 0644, NULL, &proc_dointvec},
218#ifdef CONFIG_KMOD
219 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
220 0644, NULL, &proc_dostring, &sysctl_string },
221#endif
222#ifdef CONFIG_HOTPLUG
223 {KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
224 0644, NULL, &proc_dostring, &sysctl_string },
225#endif
226#ifdef CONFIG_CHR_DEV_SG
227 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
228 0444, NULL, &proc_dointvec},
229#endif
230#ifdef CONFIG_BSD_PROCESS_ACCT
231 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
232 0644, NULL, &proc_dointvec},
233#endif
234 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
235 0444, NULL, &proc_dointvec},
236 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
237 0644, NULL, &proc_dointvec},
238#ifdef CONFIG_SYSVIPC
239 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
240 0644, NULL, &proc_doulongvec_minmax},
241 {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (size_t),
242 0644, NULL, &proc_doulongvec_minmax},
243 {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
244 0644, NULL, &proc_dointvec},
245 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
246 0644, NULL, &proc_dointvec},
247 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
248 0644, NULL, &proc_dointvec},
249 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
250 0644, NULL, &proc_dointvec},
251 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
252 0644, NULL, &proc_dointvec},
253#endif
254#ifdef CONFIG_MAGIC_SYSRQ
255 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
256 0644, NULL, &proc_dointvec},
257#endif
258 {KERN_CADPID, "cad_pid", &cad_pid, sizeof (int),
259 0600, NULL, &proc_dointvec},
260 {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
261 0644, NULL, &proc_dointvec},
262 {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
263 {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
264 &proc_dointvec_minmax, &sysctl_intvec, NULL,
265 &minolduid, &maxolduid},
266 {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
267 &proc_dointvec_minmax, &sysctl_intvec, NULL,
268 &minolduid, &maxolduid},
269#ifdef CONFIG_ARCH_S390
270#ifdef CONFIG_MATHEMU
271 {KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings",
272 &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec},
273#endif
274 {KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug",
275 &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec},
276#endif
277#ifdef __x86_64__
278 {KERN_EXCEPTION_TRACE,"exception-trace",
279 &exception_trace,sizeof(int),0644,NULL,&proc_dointvec},
280#endif
281 {0}
282};
283
284static ctl_table vm_table[] = {
285 {VM_GFP_DEBUG, "vm_gfp_debug",
286 &vm_gfp_debug, sizeof(int), 0644, NULL, &proc_dointvec},
287 {VM_VFS_SCAN_RATIO, "vm_vfs_scan_ratio",
288 &vm_vfs_scan_ratio, sizeof(int), 0644, NULL, &proc_dointvec},
289 {VM_CACHE_SCAN_RATIO, "vm_cache_scan_ratio",
290 &vm_cache_scan_ratio, sizeof(int), 0644, NULL, &proc_dointvec},
291 {VM_MAPPED_RATIO, "vm_mapped_ratio",
292 &vm_mapped_ratio, sizeof(int), 0644, NULL, &proc_dointvec},
293 {VM_LRU_BALANCE_RATIO, "vm_lru_balance_ratio",
294 &vm_lru_balance_ratio, sizeof(int), 0644, NULL, &proc_dointvec},
295 {VM_PASSES, "vm_passes",
296 &vm_passes, sizeof(int), 0644, NULL, &proc_dointvec},
297 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
298 &proc_dointvec_minmax, &sysctl_intvec, NULL,
299 &bdflush_min, &bdflush_max},
300 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
301 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
302 {VM_PAGERDAEMON, "kswapd",
303 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
304 {VM_PGT_CACHE, "pagetable_cache",
305 &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
306 {VM_PAGE_CLUSTER, "page-cluster",
307 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
308 {VM_MIN_READAHEAD, "min-readahead",
309 &vm_min_readahead,sizeof(int), 0644, NULL, &proc_dointvec},
310 {VM_MAX_READAHEAD, "max-readahead",
311 &vm_max_readahead,sizeof(int), 0644, NULL, &proc_dointvec},
312 {VM_MAX_MAP_COUNT, "max_map_count",
313 &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec},
314 {VM_LAPTOP_MODE, "laptop_mode",
315 &laptop_mode, sizeof(int), 0644, NULL, &proc_dointvec},
316 {VM_BLOCK_DUMP, "block_dump",
317 &block_dump, sizeof(int), 0644, NULL, &proc_dointvec},
318 {0}
319};
320
321static ctl_table proc_table[] = {
322 {0}
323};
324
325static ctl_table fs_table[] = {
326 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
327 0444, NULL, &proc_dointvec},
328 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
329 0444, NULL, &proc_dointvec},
330 {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
331 0444, NULL, &proc_dointvec},
332 {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
333 0644, NULL, &proc_dointvec},
334 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
335 0444, NULL, &proc_dointvec},
336 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
337 &proc_dointvec_minmax, &sysctl_intvec, NULL,
338 &minolduid, &maxolduid},
339 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
340 &proc_dointvec_minmax, &sysctl_intvec, NULL,
341 &minolduid, &maxolduid},
342 {FS_LEASES, "leases-enable", &leases_enable, sizeof(int),
343 0644, NULL, &proc_dointvec},
344 {FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable,
345 sizeof(int), 0644, NULL, &proc_dointvec},
346 {FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int),
347 0644, NULL, &proc_dointvec},
348 {0}
349};
350
351static ctl_table debug_table[] = {
352 {0}
353};
354
355static ctl_table dev_table[] = {
356 {0}
357};
358
359extern void init_irq_proc (void);
360
361void __init sysctl_init(void)
362{
363#ifdef CONFIG_PROC_FS
364 register_proc_table(root_table, proc_sys_root);
365 init_irq_proc();
366#endif
367}
368
369int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
370 void *newval, size_t newlen)
371{
372 struct list_head *tmp;
373
374 if (nlen <= 0 || nlen >= CTL_MAXNAME)
375 return -ENOTDIR;
376 if (oldval) {
377 int old_len;
378 if (!oldlenp || get_user(old_len, oldlenp))
379 return -EFAULT;
380 }
381 tmp = &root_table_header.ctl_entry;
382 do {
383 struct ctl_table_header *head =
384 list_entry(tmp, struct ctl_table_header, ctl_entry);
385 void *context = NULL;
386 int error = parse_table(name, nlen, oldval, oldlenp,
387 newval, newlen, head->ctl_table,
388 &context);
389 if (context)
390 kfree(context);
391 if (error != -ENOTDIR)
392 return error;
393 tmp = tmp->next;
394 } while (tmp != &root_table_header.ctl_entry);
395 return -ENOTDIR;
396}
397
398extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
399{
400 struct __sysctl_args tmp;
401 int error;
402
403 if (copy_from_user(&tmp, args, sizeof(tmp)))
404 return -EFAULT;
405
406 lock_kernel();
407 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
408 tmp.newval, tmp.newlen);
409 unlock_kernel();
410 return error;
411}
412
413
414
415
416
417
418static int test_perm(int mode, int op)
419{
420 if (!current->euid)
421 mode >>= 6;
422 else if (in_egroup_p(0))
423 mode >>= 3;
424 if ((mode & op & 0007) == op)
425 return 0;
426 return -EACCES;
427}
428
429static inline int ctl_perm(ctl_table *table, int op)
430{
431 return test_perm(table->mode, op);
432}
433
434static int parse_table(int *name, int nlen,
435 void *oldval, size_t *oldlenp,
436 void *newval, size_t newlen,
437 ctl_table *table, void **context)
438{
439 int n;
440repeat:
441 if (!nlen)
442 return -ENOTDIR;
443 if (get_user(n, name))
444 return -EFAULT;
445 for ( ; table->ctl_name; table++) {
446 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
447 int error;
448 if (table->child) {
449 if (ctl_perm(table, 001))
450 return -EPERM;
451 if (table->strategy) {
452 error = table->strategy(
453 table, name, nlen,
454 oldval, oldlenp,
455 newval, newlen, context);
456 if (error)
457 return error;
458 }
459 name++;
460 nlen--;
461 table = table->child;
462 goto repeat;
463 }
464 error = do_sysctl_strategy(table, name, nlen,
465 oldval, oldlenp,
466 newval, newlen, context);
467 return error;
468 }
469 }
470 return -ENOTDIR;
471}
472
473
474int do_sysctl_strategy (ctl_table *table,
475 int *name, int nlen,
476 void *oldval, size_t *oldlenp,
477 void *newval, size_t newlen, void **context)
478{
479 int op = 0, rc;
480 size_t len;
481
482 if (oldval)
483 op |= 004;
484 if (newval)
485 op |= 002;
486 if (ctl_perm(table, op))
487 return -EPERM;
488
489 if (table->strategy) {
490 rc = table->strategy(table, name, nlen, oldval, oldlenp,
491 newval, newlen, context);
492 if (rc < 0)
493 return rc;
494 if (rc > 0)
495 return 0;
496 }
497
498
499
500 if (table->data && table->maxlen) {
501 if (oldval && oldlenp) {
502 if (get_user(len, oldlenp))
503 return -EFAULT;
504 if (len) {
505 if (len > table->maxlen)
506 len = table->maxlen;
507 if(copy_to_user(oldval, table->data, len))
508 return -EFAULT;
509 if(put_user(len, oldlenp))
510 return -EFAULT;
511 }
512 }
513 if (newval && newlen) {
514 len = newlen;
515 if (len > table->maxlen)
516 len = table->maxlen;
517 if(copy_from_user(table->data, newval, len))
518 return -EFAULT;
519 }
520 }
521 return 0;
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
591
592
593struct ctl_table_header *register_sysctl_table(ctl_table * table,
594 int insert_at_head)
595{
596 struct ctl_table_header *tmp;
597 tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
598 if (!tmp)
599 return NULL;
600 tmp->ctl_table = table;
601 INIT_LIST_HEAD(&tmp->ctl_entry);
602 if (insert_at_head)
603 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
604 else
605 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
606#ifdef CONFIG_PROC_FS
607 register_proc_table(table, proc_sys_root);
608#endif
609 return tmp;
610}
611
612
613
614
615
616
617
618
619void unregister_sysctl_table(struct ctl_table_header * header)
620{
621 list_del(&header->ctl_entry);
622#ifdef CONFIG_PROC_FS
623 unregister_proc_table(header->ctl_table, proc_sys_root);
624#endif
625 kfree(header);
626}
627
628
629
630
631
632#ifdef CONFIG_PROC_FS
633
634
635static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
636{
637 struct proc_dir_entry *de;
638 int len;
639 mode_t mode;
640
641 for (; table->ctl_name; table++) {
642
643 if (!table->procname)
644 continue;
645
646 if (!table->proc_handler && !table->child) {
647 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
648 table->procname);
649 continue;
650 }
651
652 len = strlen(table->procname);
653 mode = table->mode;
654
655 de = NULL;
656 if (table->proc_handler)
657 mode |= S_IFREG;
658 else {
659 mode |= S_IFDIR;
660 for (de = root->subdir; de; de = de->next) {
661 if (proc_match(len, table->procname, de))
662 break;
663 }
664
665 }
666
667 if (!de) {
668 de = create_proc_entry(table->procname, mode, root);
669 if (!de)
670 continue;
671 de->data = (void *) table;
672 if (table->proc_handler) {
673 de->proc_fops = &proc_sys_file_operations;
674 de->proc_iops = &proc_sys_inode_operations;
675 }
676 }
677 table->de = de;
678 if (de->mode & S_IFDIR)
679 register_proc_table(table->child, de);
680 }
681}
682
683
684
685
686static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
687{
688 struct proc_dir_entry *de;
689 for (; table->ctl_name; table++) {
690 if (!(de = table->de))
691 continue;
692 if (de->mode & S_IFDIR) {
693 if (!table->child) {
694 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
695 continue;
696 }
697 unregister_proc_table(table->child, de);
698
699
700 if (de->subdir)
701 continue;
702 }
703
704
705 if (atomic_read(&de->count))
706 continue;
707
708 table->de = NULL;
709 remove_proc_entry(table->procname, root);
710 }
711}
712
713static ssize_t do_rw_proc(int write, struct file * file, char * buf,
714 size_t count, loff_t *ppos)
715{
716 int op;
717 struct proc_dir_entry *de;
718 struct ctl_table *table;
719 size_t res;
720 ssize_t error;
721
722 de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
723 if (!de || !de->data)
724 return -ENOTDIR;
725 table = (struct ctl_table *) de->data;
726 if (!table || !table->proc_handler)
727 return -ENOTDIR;
728 op = (write ? 002 : 004);
729 if (ctl_perm(table, op))
730 return -EPERM;
731
732 res = count;
733
734
735
736
737
738 error = (*table->proc_handler) (table, write, file, buf, &res);
739 if (error)
740 return error;
741 return res;
742}
743
744static ssize_t proc_readsys(struct file * file, char * buf,
745 size_t count, loff_t *ppos)
746{
747 return do_rw_proc(0, file, buf, count, ppos);
748}
749
750static ssize_t proc_writesys(struct file * file, const char * buf,
751 size_t count, loff_t *ppos)
752{
753 return do_rw_proc(1, file, (char *) buf, count, ppos);
754}
755
756static int proc_sys_permission(struct inode *inode, int op)
757{
758 return test_perm(inode->i_mode, op);
759}
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778int proc_dostring(ctl_table *table, int write, struct file *filp,
779 void *buffer, size_t *lenp)
780{
781 size_t len;
782 char *p, c;
783
784 if (!table->data || !table->maxlen || !*lenp ||
785 (filp->f_pos && !write)) {
786 *lenp = 0;
787 return 0;
788 }
789
790 if (write) {
791 len = 0;
792 p = buffer;
793 while (len < *lenp) {
794 if (get_user(c, p++))
795 return -EFAULT;
796 if (c == 0 || c == '\n')
797 break;
798 len++;
799 }
800 if (len >= table->maxlen)
801 len = table->maxlen-1;
802 if(copy_from_user(table->data, buffer, len))
803 return -EFAULT;
804 ((char *) table->data)[len] = 0;
805 filp->f_pos += *lenp;
806 } else {
807 len = strlen(table->data);
808 if (len > table->maxlen)
809 len = table->maxlen;
810 if (len > *lenp)
811 len = *lenp;
812 if (len)
813 if(copy_to_user(buffer, table->data, len))
814 return -EFAULT;
815 if (len < *lenp) {
816 if(put_user('\n', ((char *) buffer) + len))
817 return -EFAULT;
818 len++;
819 }
820 *lenp = len;
821 filp->f_pos += len;
822 }
823 return 0;
824}
825
826
827
828
829
830
831static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
832 void *buffer, size_t *lenp)
833{
834 int r;
835
836 if (!write) {
837 down_read(&uts_sem);
838 r=proc_dostring(table,0,filp,buffer,lenp);
839 up_read(&uts_sem);
840 } else {
841 down_write(&uts_sem);
842 r=proc_dostring(table,1,filp,buffer,lenp);
843 up_write(&uts_sem);
844 }
845 return r;
846}
847
848#define OP_SET 0
849#define OP_AND 1
850#define OP_OR 2
851#define OP_MAX 3
852#define OP_MIN 4
853
854static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
855 void *buffer, size_t *lenp, int conv, int op)
856{
857 int *i, vleft, first=1, neg, val;
858 size_t left, len;
859
860 #define TMPBUFLEN 20
861 char buf[TMPBUFLEN], *p;
862
863 if (!table->data || !table->maxlen || !*lenp ||
864 (filp->f_pos && !write)) {
865 *lenp = 0;
866 return 0;
867 }
868
869 i = (int *) table->data;
870 vleft = table->maxlen / sizeof(int);
871 left = *lenp;
872
873 for (; left && vleft--; i++, first=0) {
874 if (write) {
875 while (left) {
876 char c;
877 if (get_user(c, (char *) buffer))
878 return -EFAULT;
879 if (!isspace(c))
880 break;
881 left--;
882 buffer++;
883 }
884 if (!left)
885 break;
886 neg = 0;
887 len = left;
888 if (len > TMPBUFLEN-1)
889 len = TMPBUFLEN-1;
890 if(copy_from_user(buf, buffer, len))
891 return -EFAULT;
892 buf[len] = 0;
893 p = buf;
894 if (*p == '-' && left > 1) {
895 neg = 1;
896 left--, p++;
897 }
898 if (*p < '0' || *p > '9')
899 break;
900 val = simple_strtoul(p, &p, 0) * conv;
901 len = p-buf;
902 if ((len < left) && *p && !isspace(*p))
903 break;
904 if (neg)
905 val = -val;
906 buffer += len;
907 left -= len;
908 switch(op) {
909 case OP_SET: *i = val; break;
910 case OP_AND: *i &= val; break;
911 case OP_OR: *i |= val; break;
912 case OP_MAX: if(*i < val)
913 *i = val;
914 break;
915 case OP_MIN: if(*i > val)
916 *i = val;
917 break;
918 }
919 } else {
920 p = buf;
921 if (!first)
922 *p++ = '\t';
923 sprintf(p, "%d", (*i) / conv);
924 len = strlen(buf);
925 if (len > left)
926 len = left;
927 if(copy_to_user(buffer, buf, len))
928 return -EFAULT;
929 left -= len;
930 buffer += len;
931 }
932 }
933
934 if (!write && !first && left) {
935 if(put_user('\n', (char *) buffer))
936 return -EFAULT;
937 left--, buffer++;
938 }
939 if (write) {
940 p = (char *) buffer;
941 while (left) {
942 char c;
943 if (get_user(c, p++))
944 return -EFAULT;
945 if (!isspace(c))
946 break;
947 left--;
948 }
949 }
950 if (write && first)
951 return -EINVAL;
952 *lenp -= left;
953 filp->f_pos += *lenp;
954 return 0;
955}
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970int proc_dointvec(ctl_table *table, int write, struct file *filp,
971 void *buffer, size_t *lenp)
972{
973 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
974}
975
976
977
978
979
980int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
981 void *buffer, size_t *lenp)
982{
983 if (!capable(CAP_SYS_MODULE)) {
984 return -EPERM;
985 }
986 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
987 (current->pid == 1) ? OP_SET : OP_AND);
988}
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1007 void *buffer, size_t *lenp)
1008{
1009 int *i, *min, *max, vleft, first=1, neg, val;
1010 size_t len, left;
1011 #define TMPBUFLEN 20
1012 char buf[TMPBUFLEN], *p;
1013
1014 if (!table->data || !table->maxlen || !*lenp ||
1015 (filp->f_pos && !write)) {
1016 *lenp = 0;
1017 return 0;
1018 }
1019
1020 i = (int *) table->data;
1021 min = (int *) table->extra1;
1022 max = (int *) table->extra2;
1023 vleft = table->maxlen / sizeof(int);
1024 left = *lenp;
1025
1026 for (; left && vleft--; i++, min++, max++, first=0) {
1027 if (write) {
1028 while (left) {
1029 char c;
1030 if (get_user(c, (char *) buffer))
1031 return -EFAULT;
1032 if (!isspace(c))
1033 break;
1034 left--;
1035 buffer++;
1036 }
1037 if (!left)
1038 break;
1039 neg = 0;
1040 len = left;
1041 if (len > TMPBUFLEN-1)
1042 len = TMPBUFLEN-1;
1043 if(copy_from_user(buf, buffer, len))
1044 return -EFAULT;
1045 buf[len] = 0;
1046 p = buf;
1047 if (*p == '-' && left > 1) {
1048 neg = 1;
1049 left--, p++;
1050 }
1051 if (*p < '0' || *p > '9')
1052 break;
1053 val = simple_strtoul(p, &p, 0);
1054 len = p-buf;
1055 if ((len < left) && *p && !isspace(*p))
1056 break;
1057 if (neg)
1058 val = -val;
1059 buffer += len;
1060 left -= len;
1061
1062 if ((min && val < *min) || (max && val > *max))
1063 continue;
1064 *i = val;
1065 } else {
1066 p = buf;
1067 if (!first)
1068 *p++ = '\t';
1069 sprintf(p, "%d", *i);
1070 len = strlen(buf);
1071 if (len > left)
1072 len = left;
1073 if(copy_to_user(buffer, buf, len))
1074 return -EFAULT;
1075 left -= len;
1076 buffer += len;
1077 }
1078 }
1079
1080 if (!write && !first && left) {
1081 if(put_user('\n', (char *) buffer))
1082 return -EFAULT;
1083 left--, buffer++;
1084 }
1085 if (write) {
1086 p = (char *) buffer;
1087 while (left) {
1088 char c;
1089 if (get_user(c, p++))
1090 return -EFAULT;
1091 if (!isspace(c))
1092 break;
1093 left--;
1094 }
1095 }
1096 if (write && first)
1097 return -EINVAL;
1098 *lenp -= left;
1099 filp->f_pos += *lenp;
1100 return 0;
1101}
1102
1103static int do_proc_doulongvec_minmax(ctl_table *table, int write,
1104 struct file *filp,
1105 void *buffer, size_t *lenp,
1106 unsigned long convmul,
1107 unsigned long convdiv)
1108{
1109#define TMPBUFLEN 20
1110 unsigned long *i, *min, *max, val;
1111 int vleft, first=1, neg;
1112 size_t len, left;
1113 char buf[TMPBUFLEN], *p;
1114
1115 if (!table->data || !table->maxlen || !*lenp ||
1116 (filp->f_pos && !write)) {
1117 *lenp = 0;
1118 return 0;
1119 }
1120
1121 i = (unsigned long *) table->data;
1122 min = (unsigned long *) table->extra1;
1123 max = (unsigned long *) table->extra2;
1124 vleft = table->maxlen / sizeof(unsigned long);
1125 left = *lenp;
1126
1127 for (; left && vleft--; i++, first=0) {
1128 if (write) {
1129 while (left) {
1130 char c;
1131 if (get_user(c, (char *) buffer))
1132 return -EFAULT;
1133 if (!isspace(c))
1134 break;
1135 left--;
1136 buffer++;
1137 }
1138 if (!left)
1139 break;
1140 neg = 0;
1141 len = left;
1142 if (len > TMPBUFLEN-1)
1143 len = TMPBUFLEN-1;
1144 if(copy_from_user(buf, buffer, len))
1145 return -EFAULT;
1146 buf[len] = 0;
1147 p = buf;
1148 if (*p == '-' && left > 1) {
1149 neg = 1;
1150 left--, p++;
1151 }
1152 if (*p < '0' || *p > '9')
1153 break;
1154 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
1155 len = p-buf;
1156 if ((len < left) && *p && !isspace(*p))
1157 break;
1158 if (neg)
1159 val = -val;
1160 buffer += len;
1161 left -= len;
1162
1163 if(neg)
1164 continue;
1165 if (min && val < *min++)
1166 continue;
1167 if (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 if (get_user(value, vec + i))
1406 return -EFAULT;
1407 if (min && value < min[i])
1408 return -EINVAL;
1409 if (max && value > max[i])
1410 return -EINVAL;
1411 }
1412 }
1413 return 0;
1414}
1415
1416
1417int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1418 void *oldval, size_t *oldlenp,
1419 void *newval, size_t newlen, void **context)
1420{
1421 if (oldval) {
1422 size_t olen;
1423 if (oldlenp) {
1424 if (get_user(olen, oldlenp))
1425 return -EFAULT;
1426 if (olen!=sizeof(int))
1427 return -EINVAL;
1428 }
1429 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1430 (oldlenp && put_user(sizeof(int),oldlenp)))
1431 return -EFAULT;
1432 }
1433 if (newval && newlen) {
1434 int new;
1435 if (newlen != sizeof(int))
1436 return -EINVAL;
1437 if (get_user(new, (int *)newval))
1438 return -EFAULT;
1439 *(int *)(table->data) = new*HZ;
1440 }
1441 return 1;
1442}
1443
1444
1445#else
1446
1447
1448extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1449{
1450 return -ENOSYS;
1451}
1452
1453int sysctl_string(ctl_table *table, int *name, int nlen,
1454 void *oldval, size_t *oldlenp,
1455 void *newval, size_t newlen, void **context)
1456{
1457 return -ENOSYS;
1458}
1459
1460int sysctl_intvec(ctl_table *table, int *name, int nlen,
1461 void *oldval, size_t *oldlenp,
1462 void *newval, size_t newlen, void **context)
1463{
1464 return -ENOSYS;
1465}
1466
1467int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1468 void *oldval, size_t *oldlenp,
1469 void *newval, size_t newlen, void **context)
1470{
1471 return -ENOSYS;
1472}
1473
1474int proc_dostring(ctl_table *table, int write, struct file *filp,
1475 void *buffer, size_t *lenp)
1476{
1477 return -ENOSYS;
1478}
1479
1480int proc_dointvec(ctl_table *table, int write, struct file *filp,
1481 void *buffer, size_t *lenp)
1482{
1483 return -ENOSYS;
1484}
1485
1486int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1487 void *buffer, size_t *lenp)
1488{
1489 return -ENOSYS;
1490}
1491
1492int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1493 void *buffer, size_t *lenp)
1494{
1495 return -ENOSYS;
1496}
1497
1498int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1499 void *buffer, size_t *lenp)
1500{
1501 return -ENOSYS;
1502}
1503
1504int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1505 void *buffer, size_t *lenp)
1506{
1507 return -ENOSYS;
1508}
1509
1510int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1511 struct file *filp,
1512 void *buffer, size_t *lenp)
1513{
1514 return -ENOSYS;
1515}
1516
1517struct ctl_table_header * register_sysctl_table(ctl_table * table,
1518 int insert_at_head)
1519{
1520 return 0;
1521}
1522
1523void unregister_sysctl_table(struct ctl_table_header * table)
1524{
1525}
1526
1527#endif
1528