1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/config.h>
15#include <linux/sched.h>
16#include <linux/mm.h>
17#include <linux/sysctl.h>
18#include <linux/swapctl.h>
19#include <linux/proc_fs.h>
20#include <linux/malloc.h>
21#include <linux/stat.h>
22#include <linux/ctype.h>
23#include <linux/utsname.h>
24#include <linux/swapctl.h>
25#include <linux/smp.h>
26#include <linux/smp_lock.h>
27#include <linux/init.h>
28
29#include <asm/bitops.h>
30#include <asm/uaccess.h>
31
32#ifdef CONFIG_ROOT_NFS
33#include <linux/nfs_fs.h>
34#endif
35
36#ifdef CONFIG_SYSCTL
37
38
39extern int panic_timeout;
40extern int console_loglevel, C_A_D, swapout_interval;
41extern int bdf_prm[], bdflush_min[], bdflush_max[];
42extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
43extern int sysctl_overcommit_memory;
44
45#ifdef __sparc__
46extern char reboot_command [];
47#endif
48
49static int parse_table(int *, int, void *, size_t *, void *, size_t,
50 ctl_table *, void **);
51static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
52 void *, size_t, void **);
53
54
55static ctl_table root_table[];
56static struct ctl_table_header root_table_header =
57 {root_table, DNODE_SINGLE(&root_table_header)};
58
59static ctl_table kern_table[];
60static ctl_table vm_table[];
61extern ctl_table net_table[];
62static ctl_table proc_table[];
63static ctl_table fs_table[];
64static ctl_table debug_table[];
65static ctl_table dev_table[];
66
67
68
69
70#ifdef CONFIG_PROC_FS
71
72static long proc_readsys(struct inode * inode, struct file * file,
73 char * buf, unsigned long count);
74static long proc_writesys(struct inode * inode, struct file * file,
75 const char * buf, unsigned long count);
76static int proc_sys_permission(struct inode *, int);
77
78struct file_operations proc_sys_file_operations =
79{
80 NULL,
81 proc_readsys,
82 proc_writesys,
83 NULL,
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 NULL,
89 NULL
90};
91
92struct inode_operations proc_sys_inode_operations =
93{
94 &proc_sys_file_operations,
95 NULL,
96 NULL,
97 NULL,
98 NULL,
99 NULL,
100 NULL,
101 NULL,
102 NULL,
103 NULL,
104 NULL,
105 NULL,
106 NULL,
107 NULL,
108 NULL,
109 NULL,
110 proc_sys_permission
111};
112
113extern struct proc_dir_entry proc_sys_root;
114
115extern int inodes_stat[];
116static void register_proc_table(ctl_table *, struct proc_dir_entry *);
117static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
118#endif
119
120
121
122static ctl_table root_table[] = {
123 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
124 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
125 {CTL_NET, "net", NULL, 0, 0555, net_table},
126 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
127 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
128 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
129 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
130 {0}
131};
132
133static ctl_table kern_table[] = {
134 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
135 0444, NULL, &proc_dostring, &sysctl_string},
136 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
137 0444, NULL, &proc_dostring, &sysctl_string},
138 {KERN_VERSION, "version", system_utsname.version, 64,
139 0444, NULL, &proc_dostring, &sysctl_string},
140 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
141 0644, NULL, &proc_dostring, &sysctl_string},
142 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
143 0644, NULL, &proc_dostring, &sysctl_string},
144 {KERN_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
145 0444, NULL, &proc_dointvec},
146 {KERN_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
147 0444, NULL, &proc_dointvec},
148 {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
149 0644, NULL, &proc_dointvec},
150 {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
151 0444, NULL, &proc_dointvec},
152 {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
153 0644, NULL, &proc_dointvec},
154 {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
155 0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
156 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
157 0644, NULL, &proc_dointvec},
158#ifdef CONFIG_BLK_DEV_INITRD
159 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
160 0644, NULL, &proc_dointvec},
161#endif
162#ifdef CONFIG_ROOT_NFS
163 {KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
164 0644, NULL, &proc_dostring, &sysctl_string },
165 {KERN_NFSRADDRS, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
166 0644, NULL, &proc_dostring, &sysctl_string },
167#endif
168#ifdef CONFIG_BINFMT_JAVA
169 {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
170 64, 0644, NULL, &proc_dostring, &sysctl_string },
171 {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
172 64, 0644, NULL, &proc_dostring, &sysctl_string },
173#endif
174#ifdef __sparc__
175 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
176 256, 0644, NULL, &proc_dostring, &sysctl_string },
177#endif
178 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
179 0644, NULL, &proc_dointvec},
180 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
181 0644, NULL, &proc_dointvec},
182 {0}
183};
184
185static ctl_table vm_table[] = {
186 {VM_SWAPCTL, "swapctl",
187 &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
188 {VM_SWAPOUT, "swapout_interval",
189 &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies},
190 {VM_FREEPG, "freepages",
191 &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
192 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
193 &proc_dointvec_minmax, &sysctl_intvec, NULL,
194 &bdflush_min, &bdflush_max},
195 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
196 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
197 {0}
198};
199
200static ctl_table proc_table[] = {
201 {0}
202};
203
204static ctl_table fs_table[] = {
205 {0}
206};
207
208static ctl_table debug_table[] = {
209 {0}
210};
211
212static ctl_table dev_table[] = {
213 {0}
214};
215
216
217__initfunc(void sysctl_init(void))
218{
219#ifdef CONFIG_PROC_FS
220 register_proc_table(root_table, &proc_sys_root);
221#endif
222}
223
224
225int do_sysctl (int *name, int nlen,
226 void *oldval, size_t *oldlenp,
227 void *newval, size_t newlen)
228{
229 int error;
230 struct ctl_table_header *tmp;
231 void *context;
232
233 if (nlen == 0 || nlen >= CTL_MAXNAME)
234 return -ENOTDIR;
235
236 if (oldval)
237 {
238 int old_len;
239 if (!oldlenp)
240 return -EFAULT;
241 if(get_user(old_len, oldlenp))
242 return -EFAULT;
243 }
244 tmp = &root_table_header;
245 do {
246 context = NULL;
247 error = parse_table(name, nlen, oldval, oldlenp,
248 newval, newlen, tmp->ctl_table, &context);
249 if (context)
250 kfree(context);
251 if (error != -ENOTDIR)
252 return error;
253 tmp = tmp->DLIST_NEXT(ctl_entry);
254 } while (tmp != &root_table_header);
255 return -ENOTDIR;
256}
257
258extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
259{
260 struct __sysctl_args tmp;
261 int error;
262
263 if(copy_from_user(&tmp, args, sizeof(tmp)))
264 return -EFAULT;
265
266 lock_kernel();
267 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
268 tmp.newval, tmp.newlen);
269 unlock_kernel();
270 return error;
271}
272
273
274static int in_egroup_p(gid_t grp)
275{
276 if (grp != current->egid) {
277 int i = current->ngroups;
278 if (i) {
279 gid_t *groups = current->groups;
280 do {
281 if (*groups == grp)
282 goto out;
283 groups++;
284 i--;
285 } while (i);
286 }
287 return 0;
288 }
289out:
290 return 1;
291}
292
293
294
295
296static int test_perm(int mode, int op)
297{
298 if (!current->euid)
299 mode >>= 6;
300 else if (in_egroup_p(0))
301 mode >>= 3;
302 if ((mode & op & 0007) == op)
303 return 0;
304 return -EACCES;
305}
306
307static inline int ctl_perm(ctl_table *table, int op)
308{
309 return test_perm(table->mode, op);
310}
311
312static int parse_table(int *name, int nlen,
313 void *oldval, size_t *oldlenp,
314 void *newval, size_t newlen,
315 ctl_table *table, void **context)
316{
317 int error;
318repeat:
319 if (!nlen)
320 return -ENOTDIR;
321
322 for ( ; table->ctl_name; table++) {
323 int n;
324 if(get_user(n,name))
325 return -EFAULT;
326 if (n == table->ctl_name ||
327 table->ctl_name == CTL_ANY) {
328 if (table->child) {
329 if (ctl_perm(table, 001))
330 return -EPERM;
331 if (table->strategy) {
332 error = table->strategy(
333 table, name, nlen,
334 oldval, oldlenp,
335 newval, newlen, context);
336 if (error)
337 return error;
338 }
339 name++;
340 nlen--;
341 table = table->child;
342 goto repeat;
343 }
344 error = do_sysctl_strategy(table, name, nlen,
345 oldval, oldlenp,
346 newval, newlen, context);
347 return error;
348 }
349 };
350 return -ENOTDIR;
351}
352
353
354int do_sysctl_strategy (ctl_table *table,
355 int *name, int nlen,
356 void *oldval, size_t *oldlenp,
357 void *newval, size_t newlen, void **context)
358{
359 int op = 0, rc, len;
360
361 if (oldval)
362 op |= 004;
363 if (newval)
364 op |= 002;
365 if (ctl_perm(table, op))
366 return -EPERM;
367
368 if (table->strategy) {
369 rc = table->strategy(table, name, nlen, oldval, oldlenp,
370 newval, newlen, context);
371 if (rc < 0)
372 return rc;
373 if (rc > 0)
374 return 0;
375 }
376
377
378
379 if (table->data && table->maxlen) {
380 if (oldval && oldlenp) {
381 get_user(len, oldlenp);
382 if (len) {
383 if (len > table->maxlen)
384 len = table->maxlen;
385 if(copy_to_user(oldval, table->data, len))
386 return -EFAULT;
387 if(put_user(len, oldlenp))
388 return -EFAULT;
389 }
390 }
391 if (newval && newlen) {
392 len = newlen;
393 if (len > table->maxlen)
394 len = table->maxlen;
395 if(copy_from_user(table->data, newval, len))
396 return -EFAULT;
397 }
398 }
399 return 0;
400}
401
402
403
404
405
406
407static int do_securelevel_strategy (ctl_table *table,
408 int *name, int nlen,
409 void *oldval, size_t *oldlenp,
410 void *newval, size_t newlen, void **context)
411{
412 int level;
413
414 if (newval && newlen) {
415 if (newlen != sizeof (int))
416 return -EINVAL;
417 if(copy_from_user (&level, newval, newlen))
418 return -EFAULT;
419 if (level < securelevel && current->pid != 1)
420 return -EPERM;
421 }
422 return 0;
423}
424
425struct ctl_table_header *register_sysctl_table(ctl_table * table,
426 int insert_at_head)
427{
428 struct ctl_table_header *tmp;
429 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
430 if (!tmp)
431 return 0;
432 *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
433 if (insert_at_head)
434 DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
435 else
436 DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
437#ifdef CONFIG_PROC_FS
438 register_proc_table(table, &proc_sys_root);
439#endif
440 return tmp;
441}
442
443void unregister_sysctl_table(struct ctl_table_header * table)
444{
445 DLIST_DELETE(table, ctl_entry);
446#ifdef CONFIG_PROC_FS
447 unregister_proc_table(table->ctl_table, &proc_sys_root);
448#endif
449}
450
451
452
453
454
455#ifdef CONFIG_PROC_FS
456
457
458static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
459{
460 struct proc_dir_entry *de;
461 int len;
462 mode_t mode;
463
464 for (; table->ctl_name; table++) {
465 de = 0;
466
467 if (!table->procname)
468 continue;
469
470 if (!table->proc_handler &&
471 !table->child)
472 continue;
473
474 len = strlen(table->procname);
475 mode = table->mode;
476
477 if (table->proc_handler)
478 mode |= S_IFREG;
479 else {
480 mode |= S_IFDIR;
481 for (de = root->subdir; de; de = de->next) {
482 if (proc_match(len, table->procname, de))
483 break;
484 }
485
486 }
487
488 if (!de) {
489 de = create_proc_entry(table->procname, mode, root);
490 if (!de)
491 continue;
492 de->data = (void *) table;
493 if (table->proc_handler)
494 de->ops = &proc_sys_inode_operations;
495
496 }
497 table->de = de;
498 if (de->mode & S_IFDIR)
499 register_proc_table(table->child, de);
500 }
501}
502
503static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
504{
505 struct proc_dir_entry *de;
506 for (; table->ctl_name; table++) {
507 if (!(de = table->de))
508 continue;
509 if (de->mode & S_IFDIR) {
510 if (!table->child) {
511 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
512 continue;
513 }
514 unregister_proc_table(table->child, de);
515 }
516
517
518 if (!((de->mode & S_IFDIR) && de->subdir)) {
519 proc_unregister(root, de->low_ino);
520 kfree(de);
521 }
522 }
523}
524
525
526static long do_rw_proc(int write, struct inode * inode, struct file * file,
527 char * buf, unsigned long count)
528{
529 int op;
530 struct proc_dir_entry *de;
531 struct ctl_table *table;
532 size_t res;
533 long error;
534
535 de = (struct proc_dir_entry*) inode->u.generic_ip;
536 if (!de || !de->data)
537 return -ENOTDIR;
538 table = (struct ctl_table *) de->data;
539 if (!table || !table->proc_handler)
540 return -ENOTDIR;
541 op = (write ? 002 : 004);
542 if (ctl_perm(table, op))
543 return -EPERM;
544
545 res = count;
546 error = (*table->proc_handler) (table, write, file, buf, &res);
547 if (error)
548 return error;
549 return res;
550}
551
552static long proc_readsys(struct inode * inode, struct file * file,
553 char * buf, unsigned long count)
554{
555 return do_rw_proc(0, inode, file, buf, count);
556}
557
558static long proc_writesys(struct inode * inode, struct file * file,
559 const char * buf, unsigned long count)
560{
561 return do_rw_proc(1, inode, file, (char *) buf, count);
562}
563
564static int proc_sys_permission(struct inode *inode, int op)
565{
566 return test_perm(inode->i_mode, op);
567}
568
569int proc_dostring(ctl_table *table, int write, struct file *filp,
570 void *buffer, size_t *lenp)
571{
572 int len;
573 char *p, c;
574
575 if (!table->data || !table->maxlen || !*lenp ||
576 (filp->f_pos && !write)) {
577 *lenp = 0;
578 return 0;
579 }
580
581 if (write) {
582 len = 0;
583 p = buffer;
584 while (len < *lenp) {
585 if(get_user(c, p++))
586 return -EFAULT;
587 if (c == 0 || c == '\n')
588 break;
589 len++;
590 }
591 if (len >= table->maxlen)
592 len = table->maxlen-1;
593 if(copy_from_user(table->data, buffer, len))
594 return -EFAULT;
595 ((char *) table->data)[len] = 0;
596 filp->f_pos += *lenp;
597 } else {
598 len = strlen(table->data);
599 if (len > table->maxlen)
600 len = table->maxlen;
601 if (len > *lenp)
602 len = *lenp;
603 if (len)
604 if(copy_to_user(buffer, table->data, len))
605 return -EFAULT;
606 if (len < *lenp) {
607 if(put_user('\n', ((char *) buffer) + len))
608 return -EFAULT;
609 len++;
610 }
611 *lenp = len;
612 filp->f_pos += len;
613 }
614 return 0;
615}
616
617static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
618 void *buffer, size_t *lenp, int conv)
619{
620 int *i, vleft, first=1, len, left, neg, val;
621 #define TMPBUFLEN 20
622 char buf[TMPBUFLEN], *p;
623
624 if (!table->data || !table->maxlen || !*lenp ||
625 (filp->f_pos && !write)) {
626 *lenp = 0;
627 return 0;
628 }
629
630 i = (int *) table->data;
631 vleft = table->maxlen / sizeof(int);
632 left = *lenp;
633
634 for (; left && vleft--; i++, first=0) {
635 if (write) {
636 while (left) {
637 char c;
638 if(get_user(c,(char *) buffer))
639 return -EFAULT;
640 if (!isspace(c))
641 break;
642 left--;
643 ((char *) buffer)++;
644 }
645 if (!left)
646 break;
647 neg = 0;
648 len = left;
649 if (len > TMPBUFLEN-1)
650 len = TMPBUFLEN-1;
651 if(copy_from_user(buf, buffer, len))
652 return -EFAULT;
653 buf[len] = 0;
654 p = buf;
655 if (*p == '-' && left > 1) {
656 neg = 1;
657 left--, p++;
658 }
659 if (*p < '0' || *p > '9')
660 break;
661 val = simple_strtoul(p, &p, 0) * conv;
662 len = p-buf;
663 if ((len < left) && *p && !isspace(*p))
664 break;
665 if (neg)
666 val = -val;
667 buffer += len;
668 left -= len;
669 *i = val;
670 } else {
671 p = buf;
672 if (!first)
673 *p++ = '\t';
674 sprintf(p, "%d", (*i) / conv);
675 len = strlen(buf);
676 if (len > left)
677 len = left;
678 if(copy_to_user(buffer, buf, len))
679 return -EFAULT;
680 left -= len;
681 buffer += len;
682 }
683 }
684
685 if (!write && !first && left) {
686 if(put_user('\n', (char *) buffer))
687 return -EFAULT;
688 left--, buffer++;
689 }
690 if (write) {
691 p = (char *) buffer;
692 while (left) {
693 char c;
694 if(get_user(c, p++))
695 return -EFAULT;
696 if (!isspace(c))
697 break;
698 left--;
699 }
700 }
701 if (write && first)
702 return -EINVAL;
703 *lenp -= left;
704 filp->f_pos += *lenp;
705 return 0;
706}
707
708int proc_dointvec(ctl_table *table, int write, struct file *filp,
709 void *buffer, size_t *lenp)
710{
711 return do_proc_dointvec(table,write,filp,buffer,lenp,1);
712}
713
714int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
715 void *buffer, size_t *lenp)
716{
717 int *i, *min, *max, vleft, first=1, len, left, neg, val;
718 #define TMPBUFLEN 20
719 char buf[TMPBUFLEN], *p;
720
721 if (!table->data || !table->maxlen || !*lenp ||
722 (filp->f_pos && !write)) {
723 *lenp = 0;
724 return 0;
725 }
726
727 i = (int *) table->data;
728 min = (int *) table->extra1;
729 max = (int *) table->extra2;
730 vleft = table->maxlen / sizeof(int);
731 left = *lenp;
732
733 for (; left && vleft--; i++, first=0) {
734 if (write) {
735 while (left) {
736 char c;
737 if(get_user(c, (char *) buffer))
738 return -EFAULT;
739 if (!isspace(c))
740 break;
741 left--;
742 ((char *) buffer)++;
743 }
744 if (!left)
745 break;
746 neg = 0;
747 len = left;
748 if (len > TMPBUFLEN-1)
749 len = TMPBUFLEN-1;
750 if(copy_from_user(buf, buffer, len))
751 return -EFAULT;
752 buf[len] = 0;
753 p = buf;
754 if (*p == '-' && left > 1) {
755 neg = 1;
756 left--, p++;
757 }
758 if (*p < '0' || *p > '9')
759 break;
760 val = simple_strtoul(p, &p, 0);
761 len = p-buf;
762 if ((len < left) && *p && !isspace(*p))
763 break;
764 if (neg)
765 val = -val;
766 buffer += len;
767 left -= len;
768
769 if (min && val < *min++)
770 continue;
771 if (max && val > *max++)
772 continue;
773 *i = val;
774 } else {
775 p = buf;
776 if (!first)
777 *p++ = '\t';
778 sprintf(p, "%d", *i);
779 len = strlen(buf);
780 if (len > left)
781 len = left;
782 if(copy_to_user(buffer, buf, len))
783 return -EFAULT;
784 left -= len;
785 buffer += len;
786 }
787 }
788
789 if (!write && !first && left) {
790 if(put_user('\n', (char *) buffer))
791 return -EFAULT;
792 left--, buffer++;
793 }
794 if (write) {
795 p = (char *) buffer;
796 while (left) {
797 char c;
798 if(get_user(c, p++))
799 return -EFAULT;
800 if (!isspace(c))
801 break;
802 left--;
803 }
804 }
805 if (write && first)
806 return -EINVAL;
807 *lenp -= left;
808 filp->f_pos += *lenp;
809 return 0;
810}
811
812
813int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
814 void *buffer, size_t *lenp)
815{
816 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ);
817}
818
819#else
820
821int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
822 void *buffer, size_t *lenp)
823{
824 return -ENOSYS;
825}
826
827int proc_dostring(ctl_table *table, int write, struct file *filp,
828 void *buffer, size_t *lenp)
829{
830 return -ENOSYS;
831}
832
833int proc_dointvec(ctl_table *table, int write, struct file *filp,
834 void *buffer, size_t *lenp)
835{
836 return -ENOSYS;
837}
838
839int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
840 void *buffer, size_t *lenp)
841{
842 return -ENOSYS;
843}
844
845int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
846 void *buffer, size_t *lenp)
847{
848 return -ENOSYS;
849}
850
851#endif
852
853
854
855
856
857
858
859int sysctl_string(ctl_table *table, int *name, int nlen,
860 void *oldval, size_t *oldlenp,
861 void *newval, size_t newlen, void **context)
862{
863 int l, len;
864
865 if (!table->data || !table->maxlen)
866 return -ENOTDIR;
867
868 if (oldval && oldlenp) {
869 if(get_user(len, oldlenp))
870 return -EFAULT;
871 if (len) {
872 l = strlen(table->data);
873 if (len > l) len = l;
874 if (len >= table->maxlen)
875 len = table->maxlen;
876 if(copy_to_user(oldval, table->data, len))
877 return -EFAULT;
878 if(put_user(0, ((char *) oldval) + len))
879 return -EFAULT;
880 if(put_user(len, oldlenp))
881 return -EFAULT;
882 }
883 }
884 if (newval && newlen) {
885 len = newlen;
886 if (len > table->maxlen)
887 len = table->maxlen;
888 if(copy_from_user(table->data, newval, len))
889 return -EFAULT;
890 if (len == table->maxlen)
891 len--;
892 ((char *) table->data)[len] = 0;
893#ifdef CONFIG_TRANS_NAMES
894 translations_dirty = 1;
895#endif
896 }
897 return 0;
898}
899
900
901
902
903
904
905int sysctl_intvec(ctl_table *table, int *name, int nlen,
906 void *oldval, size_t *oldlenp,
907 void *newval, size_t newlen, void **context)
908{
909 int i, length, *vec, *min, *max;
910
911 if (newval && newlen) {
912 if (newlen % sizeof(int) != 0)
913 return -EINVAL;
914
915 if (!table->extra1 && !table->extra2)
916 return 0;
917
918 if (newlen > table->maxlen)
919 newlen = table->maxlen;
920 length = newlen / sizeof(int);
921
922 vec = (int *) newval;
923 min = (int *) table->extra1;
924 max = (int *) table->extra2;
925
926 for (i = 0; i < length; i++) {
927 int value;
928 get_user(value, vec + i);
929 if (min && value < min[i])
930 return -EINVAL;
931 if (max && value > max[i])
932 return -EINVAL;
933 }
934 }
935 return 0;
936}
937
938int do_string (
939 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
940 int rdwr, char *data, size_t max)
941{
942 int l = strlen(data) + 1;
943 if (newval && !rdwr)
944 return -EPERM;
945 if (newval && newlen >= max)
946 return -EINVAL;
947 if (oldval) {
948 int old_l;
949 if(get_user(old_l, oldlenp))
950 return -EFAULT;
951 if (l > old_l)
952 return -ENOMEM;
953 if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
954 return -EFAULT;
955 }
956 if (newval) {
957 if(copy_from_user(data, newval, newlen))
958 return -EFAULT;
959 data[newlen] = 0;
960 }
961 return 0;
962}
963
964int do_int (
965 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
966 int rdwr, int *data)
967{
968 if (newval && !rdwr)
969 return -EPERM;
970 if (newval && newlen != sizeof(int))
971 return -EINVAL;
972 if (oldval) {
973 int old_l;
974 if(get_user(old_l, oldlenp))
975 return -EFAULT;
976 if (old_l < sizeof(int))
977 return -ENOMEM;
978 if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
979 return -EFAULT;
980 }
981 if (newval)
982 if(copy_from_user(data, newval, sizeof(int)))
983 return -EFAULT;
984 return 0;
985}
986
987int do_struct (
988 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
989 int rdwr, void *data, size_t len)
990{
991 if (newval && !rdwr)
992 return -EPERM;
993 if (newval && newlen != len)
994 return -EINVAL;
995 if (oldval) {
996 int old_l;
997 if(get_user(old_l, oldlenp))
998 return -EFAULT;
999 if (old_l < len)
1000 return -ENOMEM;
1001 if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
1002 return -EFAULT;
1003 }
1004 if (newval)
1005 if(copy_from_user(data, newval, len))
1006 return -EFAULT;
1007 return 0;
1008}
1009
1010
1011#else
1012
1013
1014extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
1015{
1016 return -ENOSYS;
1017}
1018
1019int sysctl_string(ctl_table *table, int *name, int nlen,
1020 void *oldval, size_t *oldlenp,
1021 void *newval, size_t newlen, void **context)
1022{
1023 return -ENOSYS;
1024}
1025
1026int sysctl_intvec(ctl_table *table, int *name, int nlen,
1027 void *oldval, size_t *oldlenp,
1028 void *newval, size_t newlen, void **context)
1029{
1030 return -ENOSYS;
1031}
1032
1033int proc_dostring(ctl_table *table, int write, struct file *filp,
1034 void *buffer, size_t *lenp)
1035{
1036 return -ENOSYS;
1037}
1038
1039int proc_dointvec(ctl_table *table, int write, struct file *filp,
1040 void *buffer, size_t *lenp)
1041{
1042 return -ENOSYS;
1043}
1044
1045int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1046 void *buffer, size_t *lenp)
1047{
1048 return -ENOSYS;
1049}
1050
1051int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1052 void *buffer, size_t *lenp)
1053{
1054 return -ENOSYS;
1055}
1056
1057struct ctl_table_header * register_sysctl_table(ctl_table * table,
1058 int insert_at_head)
1059{
1060 return 0;
1061}
1062
1063void unregister_sysctl_table(struct ctl_table_header * table)
1064{
1065}
1066
1067#endif
1068
1069
1070
1071