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