Version:
~ [ 0.6-2.3.46 ] ~
Architecture:
~ [ um ] ~
** Warning: Cannot open xref database.
1 /*
2 * sysctl.c: General linux system control interface
3 *
4 * Begun 24 March 1995, Stephen Tweedie
5 * Added /proc support, Dec 1995
6 * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
7 * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
8 * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
9 * Dynamic registration fixes, Stephen Tweedie.
10 * Added kswapd-interval, ctrl-alt-del, printk stuff, 1/8/97, Chris Horn.
11 * Made sysctl support optional via CONFIG_SYSCTL, 1/10/97, Chris
12 * Horn.
13 * Added proc_doulongvec_ms_jiffies_minmax, 09/08/99, Carlos H. Bauer.
14 * Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer.
15 */
16
17 #include <linux/config.h>
18 #include <linux/malloc.h>
19 #include <linux/sysctl.h>
20 #include <linux/swapctl.h>
21 #include <linux/proc_fs.h>
22 #include <linux/ctype.h>
23 #include <linux/utsname.h>
24 #include <linux/capability.h>
25 #include <linux/smp_lock.h>
26 #include <linux/init.h>
27 #include <linux/sysrq.h>
28 #include <linux/highuid.h>
29
30 #include <asm/uaccess.h>
31
32 #ifdef CONFIG_ROOT_NFS
33 #include <linux/nfs_fs.h>
34 #endif
35
36 #if defined(CONFIG_SYSCTL)
37
38 /* External variables not in a header file. */
39 extern int panic_timeout;
40 extern int console_loglevel, C_A_D;
41 extern int bdf_prm[], bdflush_min[], bdflush_max[];
42 extern int sysctl_overcommit_memory;
43 extern int max_threads;
44 extern int nr_queued_signals, max_queued_signals;
45
46 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
47 static int maxolduid = 65535;
48 static int minolduid = 0;
49
50 #ifdef CONFIG_KMOD
51 extern char modprobe_path[];
52 #endif
53 #ifdef CONFIG_CHR_DEV_SG
54 extern int sg_big_buff;
55 #endif
56 #ifdef CONFIG_SYSVIPC
57 extern size_t shm_ctlmax;
58 extern int shm_ctlall;
59 extern int shm_ctlmni;
60 extern int msg_ctlmax;
61 extern int msg_ctlmnb;
62 extern int msg_ctlmni;
63 extern int sem_ctls[];
64 #endif
65
66 #ifdef __sparc__
67 extern char reboot_command [];
68 extern int stop_a_enabled;
69 #endif
70 #ifdef __powerpc__
71 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
72 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
73 void *buffer, size_t *lenp);
74 #endif
75
76 #ifdef CONFIG_BSD_PROCESS_ACCT
77 extern int acct_parm[];
78 #endif
79
80 extern int pgt_cache_water[];
81
82 static int parse_table(int *, int, void *, size_t *, void *, size_t,
83 ctl_table *, void **);
84 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
85 void *buffer, size_t *lenp);
86
87
88 static ctl_table root_table[];
89 static struct ctl_table_header root_table_header =
90 {root_table, DNODE_SINGLE(&root_table_header)};
91
92 static ctl_table kern_table[];
93 static ctl_table vm_table[];
94 #ifdef CONFIG_NET
95 extern ctl_table net_table[];
96 #endif
97 static ctl_table proc_table[];
98 static ctl_table fs_table[];
99 static ctl_table debug_table[];
100 static ctl_table dev_table[];
101 extern ctl_table random_table[];
102
103
104 /* /proc declarations: */
105
106 #ifdef CONFIG_PROC_FS
107
108 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
109 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
110 static int proc_sys_permission(struct inode *, int);
111
112 struct file_operations proc_sys_file_operations =
113 {
114 read: proc_readsys,
115 write: proc_writesys,
116 };
117
118 struct inode_operations proc_sys_inode_operations =
119 {
120 &proc_sys_file_operations,
121 NULL, /* create */
122 NULL, /* lookup */
123 NULL, /* link */
124 NULL, /* unlink */
125 NULL, /* symlink */
126 NULL, /* mkdir */
127 NULL, /* rmdir */
128 NULL, /* mknod */
129 NULL, /* rename */
130 NULL, /* readlink */
131 NULL, /* follow_link */
132 NULL, /* truncate */
133 proc_sys_permission, /* permission */
134 NULL /* revalidate */
135 };
136
137 extern struct proc_dir_entry *proc_sys_root;
138
139 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
140 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
141 #endif
142 extern int inodes_stat[];
143 extern int dentry_stat[];
144
145 /* The default sysctl tables: */
146
147 static ctl_table root_table[] = {
148 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
149 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
150 #ifdef CONFIG_NET
151 {CTL_NET, "net", NULL, 0, 0555, net_table},
152 #endif
153 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
154 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
155 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
156 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
157 {0}
158 };
159
160 static ctl_table kern_table[] = {
161 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
162 0444, NULL, &proc_doutsstring, &sysctl_string},
163 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
164 0444, NULL, &proc_doutsstring, &sysctl_string},
165 {KERN_VERSION, "version", system_utsname.version, 64,
166 0444, NULL, &proc_doutsstring, &sysctl_string},
167 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
168 0644, NULL, &proc_doutsstring, &sysctl_string},
169 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
170 0644, NULL, &proc_doutsstring, &sysctl_string},
171 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
172 0644, NULL, &proc_dointvec},
173 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
174 0600, NULL, &proc_dointvec_bset},
175 #ifdef CONFIG_BLK_DEV_INITRD
176 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
177 0644, NULL, &proc_dointvec},
178 #endif
179 #ifdef __sparc__
180 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
181 256, 0644, NULL, &proc_dostring, &sysctl_string },
182 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
183 0644, NULL, &proc_dointvec},
184 #endif
185 #ifdef __powerpc__
186 {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
187 0644, NULL, &proc_dointvec},
188 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
189 0644, NULL, &proc_dointvec},
190 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
191 0644, NULL, &proc_dointvec},
192 {KERN_PPC_L2CR, "l2cr", NULL, 0,
193 0644, NULL, &proc_dol2crvec},
194 #endif
195 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
196 0644, NULL, &proc_dointvec},
197 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
198 0644, NULL, &proc_dointvec},
199 #ifdef CONFIG_KMOD
200 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
201 0644, NULL, &proc_dostring, &sysctl_string },
202 #endif
203 #ifdef CONFIG_CHR_DEV_SG
204 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
205 0444, NULL, &proc_dointvec},
206 #endif
207 #ifdef CONFIG_BSD_PROCESS_ACCT
208 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
209 0644, NULL, &proc_dointvec},
210 #endif
211 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
212 0444, NULL, &proc_dointvec},
213 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
214 0644, NULL, &proc_dointvec},
215 #ifdef CONFIG_SYSVIPC
216 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
217 0644, NULL, &proc_doulongvec_minmax},
218 {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (int),
219 0644, NULL, &proc_dointvec},
220 {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
221 0644, NULL, &proc_dointvec},
222 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
223 0644, NULL, &proc_dointvec},
224 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
225 0644, NULL, &proc_dointvec},
226 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
227 0644, NULL, &proc_dointvec},
228 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
229 0644, NULL, &proc_dointvec},
230 #endif
231 #ifdef CONFIG_MAGIC_SYSRQ
232 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
233 0644, NULL, &proc_dointvec},
234 #endif
235 {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
236 0644, NULL, &proc_dointvec},
237 {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
238 {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
239 &proc_dointvec_minmax, &sysctl_intvec, NULL,
240 &minolduid, &maxolduid},
241 {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
242 &proc_dointvec_minmax, &sysctl_intvec, NULL,
243 &minolduid, &maxolduid},
244 {0}
245 };
246
247 static ctl_table vm_table[] = {
248 {VM_FREEPG, "freepages",
249 &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
250 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
251 &proc_dointvec_minmax, &sysctl_intvec, NULL,
252 &bdflush_min, &bdflush_max},
253 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
254 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
255 {VM_BUFFERMEM, "buffermem",
256 &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
257 {VM_PAGECACHE, "pagecache",
258 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
259 {VM_PAGERDAEMON, "kswapd",
260 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
261 {VM_PGT_CACHE, "pagetable_cache",
262 &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
263 {VM_PAGE_CLUSTER, "page-cluster",
264 &page_cluster, sizeof(int), 0600, NULL, &proc_dointvec},
265 {0}
266 };
267
268 static ctl_table proc_table[] = {
269 {0}
270 };
271
272 static ctl_table fs_table[] = {
273 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
274 0444, NULL, &proc_dointvec},
275 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
276 0444, NULL, &proc_dointvec},
277 {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
278 0444, NULL, &proc_dointvec},
279 {FS_MAXFILE, "file-max", &max_files, sizeof(int),
280 0644, NULL, &proc_dointvec},
281 {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
282 0444, NULL, &proc_dointvec},
283 {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
284 0644, NULL, &proc_dointvec},
285 {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
286 0444, NULL, &proc_dointvec},
287 {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
288 0644, NULL, &proc_dointvec},
289 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
290 0444, NULL, &proc_dointvec},
291 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
292 &proc_dointvec_minmax, &sysctl_intvec, NULL,
293 &minolduid, &maxolduid},
294 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
295 &proc_dointvec_minmax, &sysctl_intvec, NULL,
296 &minolduid, &maxolduid},
297 {0}
298 };
299
300 static ctl_table debug_table[] = {
301 {0}
302 };
303
304 static ctl_table dev_table[] = {
305 {0}
306 };
307
308
309 void __init sysctl_init(void)
310 {
311 #ifdef CONFIG_PROC_FS
312 register_proc_table(root_table, proc_sys_root);
313 #endif
314 }
315
316
317 int do_sysctl (int *name, int nlen,
318 void *oldval, size_t *oldlenp,
319 void *newval, size_t newlen)
320 {
321 int error;
322 struct ctl_table_header *tmp;
323 void *context;
324
325 if (nlen == 0 || nlen >= CTL_MAXNAME)
326 return -ENOTDIR;
327
328 if (oldval)
329 {
330 int old_len;
331 if (!oldlenp)
332 return -EFAULT;
333 if(get_user(old_len, oldlenp))
334 return -EFAULT;
335 }
336 tmp = &root_table_header;
337 do {
338 context = NULL;
339 error = parse_table(name, nlen, oldval, oldlenp,
340 newval, newlen, tmp->ctl_table, &context);
341 if (context)
342 kfree(context);
343 if (error != -ENOTDIR)
344 return error;
345 tmp = tmp->DLIST_NEXT(ctl_entry);
346 } while (tmp != &root_table_header);
347 return -ENOTDIR;
348 }
349
350 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
351 {
352 struct __sysctl_args tmp;
353 int error;
354
355 if(copy_from_user(&tmp, args, sizeof(tmp)))
356 return -EFAULT;
357
358 lock_kernel();
359 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
360 tmp.newval, tmp.newlen);
361 unlock_kernel();
362 return error;
363 }
364
365 /* ctl_perm does NOT grant the superuser all rights automatically, because
366 some sysctl variables are readonly even to root. */
367
368 static int test_perm(int mode, int op)
369 {
370 if (!current->euid)
371 mode >>= 6;
372 else if (in_egroup_p(0))
373 mode >>= 3;
374 if ((mode & op & 0007) == op)
375 return 0;
376 return -EACCES;
377 }
378
379 static inline int ctl_perm(ctl_table *table, int op)
380 {
381 return test_perm(table->mode, op);
382 }
383
384 static int parse_table(int *name, int nlen,
385 void *oldval, size_t *oldlenp,
386 void *newval, size_t newlen,
387 ctl_table *table, void **context)
388 {
389 int error;
390 repeat:
391 if (!nlen)
392 return -ENOTDIR;
393
394 for ( ; table->ctl_name; table++) {
395 int n;
396 if(get_user(n,name))
397 return -EFAULT;
398 if (n == table->ctl_name ||
399 table->ctl_name == CTL_ANY) {
400 if (table->child) {
401 if (ctl_perm(table, 001))
402 return -EPERM;
403 if (table->strategy) {
404 error = table->strategy(
405 table, name, nlen,
406 oldval, oldlenp,
407 newval, newlen, context);
408 if (error)
409 return error;
410 }
411 name++;
412 nlen--;
413 table = table->child;
414 goto repeat;
415 }
416 error = do_sysctl_strategy(table, name, nlen,
417 oldval, oldlenp,
418 newval, newlen, context);
419 return error;
420 }
421 };
422 return -ENOTDIR;
423 }
424
425 /* Perform the actual read/write of a sysctl table entry. */
426 int do_sysctl_strategy (ctl_table *table,
427 int *name, int nlen,
428 void *oldval, size_t *oldlenp,
429 void *newval, size_t newlen, void **context)
430 {
431 int op = 0, rc, len;
432
433 if (oldval)
434 op |= 004;
435 if (newval)
436 op |= 002;
437 if (ctl_perm(table, op))
438 return -EPERM;
439
440 if (table->strategy) {
441 rc = table->strategy(table, name, nlen, oldval, oldlenp,
442 newval, newlen, context);
443 if (rc < 0)
444 return rc;
445 if (rc > 0)
446 return 0;
447 }
448
449 /* If there is no strategy routine, or if the strategy returns
450 * zero, proceed with automatic r/w */
451 if (table->data && table->maxlen) {
452 if (oldval && oldlenp) {
453 get_user(len, oldlenp);
454 if (len) {
455 if (len > table->maxlen)
456 len = table->maxlen;
457 if(copy_to_user(oldval, table->data, len))
458 return -EFAULT;
459 if(put_user(len, oldlenp))
460 return -EFAULT;
461 }
462 }
463 if (newval && newlen) {
464 len = newlen;
465 if (len > table->maxlen)
466 len = table->maxlen;
467 if(copy_from_user(table->data, newval, len))
468 return -EFAULT;
469 }
470 }
471 return 0;
472 }
473
474 struct ctl_table_header *register_sysctl_table(ctl_table * table,
475 int insert_at_head)
476 {
477 struct ctl_table_header *tmp;
478 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
479 if (!tmp)
480 return 0;
481 *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
482 if (insert_at_head)
483 DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
484 else
485 DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
486 #ifdef CONFIG_PROC_FS
487 register_proc_table(table, proc_sys_root);
488 #endif
489 return tmp;
490 }
491
492 /*
493 * Unlink and free a ctl_table.
494 */
495 void unregister_sysctl_table(struct ctl_table_header * header)
496 {
497 DLIST_DELETE(header, ctl_entry);
498 #ifdef CONFIG_PROC_FS
499 unregister_proc_table(header->ctl_table, proc_sys_root);
500 #endif
501 kfree(header);
502 }
503
504 /*
505 * /proc/sys support
506 */
507
508 #ifdef CONFIG_PROC_FS
509
510 /* Scan the sysctl entries in table and add them all into /proc */
511 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
512 {
513 struct proc_dir_entry *de;
514 int len;
515 mode_t mode;
516
517 for (; table->ctl_name; table++) {
518 /* Can't do anything without a proc name. */
519 if (!table->procname)
520 continue;
521 /* Maybe we can't do anything with it... */
522 if (!table->proc_handler && !table->child) {
523 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
524 table->procname);
525 continue;
526 }
527
528 len = strlen(table->procname);
529 mode = table->mode;
530
531 de = NULL;
532 if (table->proc_handler)
533 mode |= S_IFREG;
534 else {
535 mode |= S_IFDIR;
536 for (de = root->subdir; de; de = de->next) {
537 if (proc_match(len, table->procname, de))
538 break;
539 }
540 /* If the subdir exists already, de is non-NULL */
541 }
542
543 if (!de) {
544 de = create_proc_entry(table->procname, mode, root);
545 if (!de)
546 continue;
547 de->data = (void *) table;
548 if (table->proc_handler)
549 de->ops = &proc_sys_inode_operations;
550
551 }
552 table->de = de;
553 if (de->mode & S_IFDIR)
554 register_proc_table(table->child, de);
555 }
556 }
557
558 /*
559 * Unregister a /proc sysctl table and any subdirectories.
560 */
561 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
562 {
563 struct proc_dir_entry *de;
564 for (; table->ctl_name; table++) {
565 if (!(de = table->de))
566 continue;
567 if (de->mode & S_IFDIR) {
568 if (!table->child) {
569 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
570 continue;
571 }
572 unregister_proc_table(table->child, de);
573
574 /* Don't unregister directories which still have entries.. */
575 if (de->subdir)
576 continue;
577 }
578
579 /* Don't unregister proc entries that are still being used.. */
580 if (de->count)
581 continue;
582
583 table->de = NULL;
584 remove_proc_entry(table->procname, root);
585 }
586 }
587
588 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
589 size_t count, loff_t *ppos)
590 {
591 int op;
592 struct proc_dir_entry *de;
593 struct ctl_table *table;
594 size_t res;
595 ssize_t error;
596
597 de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
598 if (!de || !de->data)
599 return -ENOTDIR;
600 table = (struct ctl_table *) de->data;
601 if (!table || !table->proc_handler)
602 return -ENOTDIR;
603 op = (write ? 002 : 004);
604 if (ctl_perm(table, op))
605 return -EPERM;
606
607 res = count;
608
609 /*
610 * FIXME: we need to pass on ppos to the handler.
611 */
612
613 error = (*table->proc_handler) (table, write, file, buf, &res);
614 if (error)
615 return error;
616 return res;
617 }
618
619 static ssize_t proc_readsys(struct file * file, char * buf,
620 size_t count, loff_t *ppos)
621 {
622 return do_rw_proc(0, file, buf, count, ppos);
623 }
624
625 static ssize_t proc_writesys(struct file * file, const char * buf,
626 size_t count, loff_t *ppos)
627 {
628 return do_rw_proc(1, file, (char *) buf, count, ppos);
629 }
630
631 static int proc_sys_permission(struct inode *inode, int op)
632 {
633 return test_perm(inode->i_mode, op);
634 }
635
636 int proc_dostring(ctl_table *table, int write, struct file *filp,
637 void *buffer, size_t *lenp)
638 {
639 int len;
640 char *p, c;
641
642 if (!table->data || !table->maxlen || !*lenp ||
643 (filp->f_pos && !write)) {
644 *lenp = 0;
645 return 0;
646 }
647
648 if (write) {
649 len = 0;
650 p = buffer;
651 while (len < *lenp) {
652 if(get_user(c, p++))
653 return -EFAULT;
654 if (c == 0 || c == '\n')
655 break;
656 len++;
657 }
658 if (len >= table->maxlen)
659 len = table->maxlen-1;
660 if(copy_from_user(table->data, buffer, len))
661 return -EFAULT;
662 ((char *) table->data)[len] = 0;
663 filp->f_pos += *lenp;
664 } else {
665 len = strlen(table->data);
666 if (len > table->maxlen)
667 len = table->maxlen;
668 if (len > *lenp)
669 len = *lenp;
670 if (len)
671 if(copy_to_user(buffer, table->data, len))
672 return -EFAULT;
673 if (len < *lenp) {
674 if(put_user('\n', ((char *) buffer) + len))
675 return -EFAULT;
676 len++;
677 }
678 *lenp = len;
679 filp->f_pos += len;
680 }
681 return 0;
682 }
683
684 /*
685 * Special case of dostring for the UTS structure. This has locks
686 * to observe. Should this be in kernel/sys.c ????
687 */
688
689 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
690 void *buffer, size_t *lenp)
691 {
692 int r;
693
694 if (!write) {
695 down_read(&uts_sem);
696 r=proc_dostring(table,0,filp,buffer,lenp);
697 up_read(&uts_sem);
698 } else {
699 down_write(&uts_sem);
700 r=proc_dostring(table,1,filp,buffer,lenp);
701 up_write(&uts_sem);
702 }
703 return r;
704 }
705
706 #define OP_SET 0
707 #define OP_AND 1
708 #define OP_OR 2
709 #define OP_MAX 3
710 #define OP_MIN 4
711 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
712 void *buffer, size_t *lenp, int conv, int op)
713 {
714 int *i, vleft, first=1, len, left, neg, val;
715 #define TMPBUFLEN 20
716 char buf[TMPBUFLEN], *p;
717
718 if (!table->data || !table->maxlen || !*lenp ||
719 (filp->f_pos && !write)) {
720 *lenp = 0;
721 return 0;
722 }
723
724 i = (int *) table->data;
725 vleft = table->maxlen / sizeof(int);
726 left = *lenp;
727
728 for (; left && vleft--; i++, first=0) {
729 if (write) {
730 while (left) {
731 char c;
732 if(get_user(c,(char *) buffer))
733 return -EFAULT;
734 if (!isspace(c))
735 break;
736 left--;
737 ((char *) buffer)++;
738 }
739 if (!left)
740 break;
741 neg = 0;
742 len = left;
743 if (len > TMPBUFLEN-1)
744 len = TMPBUFLEN-1;
745 if(copy_from_user(buf, buffer, len))
746 return -EFAULT;
747 buf[len] = 0;
748 p = buf;
749 if (*p == '-' && left > 1) {
750 neg = 1;
751 left--, p++;
752 }
753 if (*p < '' || *p > '9')
754 break;
755 val = simple_strtoul(p, &p, 0) * conv;
756 len = p-buf;
757 if ((len < left) && *p && !isspace(*p))
758 break;
759 if (neg)
760 val = -val;
761 buffer += len;
762 left -= len;
763 switch(op) {
764 case OP_SET: *i = val; break;
765 case OP_AND: *i &= val; break;
766 case OP_OR: *i |= val; break;
767 case OP_MAX: if(*i < val)
768 *i = val;
769 break;
770 case OP_MIN: if(*i > val)
771 *i = val;
772 break;
773 }
774 } else {
775 p = buf;
776 if (!first)
777 *p++ = '\t';
778 sprintf(p, "%d", (*i) / conv);
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 int proc_dointvec(ctl_table *table, int write, struct file *filp,
813 void *buffer, size_t *lenp)
814 {
815 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
816 }
817
818 /*
819 * init may raise the set.
820 */
821
822 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
823 void *buffer, size_t *lenp)
824 {
825 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
826 (current->pid == 1) ? OP_SET : OP_AND);
827 }
828
829
830 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
831 void *buffer, size_t *lenp)
832 {
833 int *i, *min, *max, vleft, first=1, len, left, neg, val;
834 #define TMPBUFLEN 20
835 char buf[TMPBUFLEN], *p;
836
837 if (!table->data || !table->maxlen || !*lenp ||
838 (filp->f_pos && !write)) {
839 *lenp = 0;
840 return 0;
841 }
842
843 i = (int *) table->data;
844 min = (int *) table->extra1;
845 max = (int *) table->extra2;
846 vleft = table->maxlen / sizeof(int);
847 left = *lenp;
848
849 for (; left && vleft--; i++, first=0) {
850 if (write) {
851 while (left) {
852 char c;
853 if(get_user(c, (char *) buffer))
854 return -EFAULT;
855 if (!isspace(c))
856 break;
857 left--;
858 ((char *) buffer)++;
859 }
860 if (!left)
861 break;
862 neg = 0;
863 len = left;
864 if (len > TMPBUFLEN-1)
865 len = TMPBUFLEN-1;
866 if(copy_from_user(buf, buffer, len))
867 return -EFAULT;
868 buf[len] = 0;
869 p = buf;
870 if (*p == '-' && left > 1) {
871 neg = 1;
872 left--, p++;
873 }
874 if (*p < '' || *p > '9')
875 break;
876 val = simple_strtoul(p, &p, 0);
877 len = p-buf;
878 if ((len < left) && *p && !isspace(*p))
879 break;
880 if (neg)
881 val = -val;
882 buffer += len;
883 left -= len;
884
885 if (min && val < *min++)
886 continue;
887 if (max && val > *max++)
888 continue;
889 *i = val;
890 } else {
891 p = buf;
892 if (!first)
893 *p++ = '\t';
894 sprintf(p, "%d", *i);
895 len = strlen(buf);
896 if (len > left)
897 len = left;
898 if(copy_to_user(buffer, buf, len))
899 return -EFAULT;
900 left -= len;
901 buffer += len;
902 }
903 }
904
905 if (!write && !first && left) {
906 if(put_user('\n', (char *) buffer))
907 return -EFAULT;
908 left--, buffer++;
909 }
910 if (write) {
911 p = (char *) buffer;
912 while (left) {
913 char c;
914 if(get_user(c, p++))
915 return -EFAULT;
916 if (!isspace(c))
917 break;
918 left--;
919 }
920 }
921 if (write && first)
922 return -EINVAL;
923 *lenp -= left;
924 filp->f_pos += *lenp;
925 return 0;
926 }
927
928
929 /*
930 * an unsigned long function version
931 */
932
933 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
934 struct file *filp,
935 void *buffer, size_t *lenp,
936 unsigned long convmul,
937 unsigned long convdiv)
938 {
939 #define TMPBUFLEN 20
940 unsigned long *i, *min, *max, val;
941 int vleft, first=1, len, left, neg;
942 char buf[TMPBUFLEN], *p;
943
944 if (!table->data || !table->maxlen || !*lenp ||
945 (filp->f_pos && !write)) {
946 *lenp = 0;
947 return 0;
948 }
949
950 i = (unsigned long *) table->data;
951 min = (unsigned long *) table->extra1;
952 max = (unsigned long *) table->extra2;
953 vleft = table->maxlen / sizeof(unsigned long);
954 left = *lenp;
955
956 for (; left && vleft--; i++, first=0) {
957 if (write) {
958 while (left) {
959 char c;
960 if(get_user(c, (char *) buffer))
961 return -EFAULT;
962 if (!isspace(c))
963 break;
964 left--;
965 ((char *) buffer)++;
966 }
967 if (!left)
968 break;
969 neg = 0;
970 len = left;
971 if (len > TMPBUFLEN-1)
972 len = TMPBUFLEN-1;
973 if(copy_from_user(buf, buffer, len))
974 return -EFAULT;
975 buf[len] = 0;
976 p = buf;
977 if (*p == '-' && left > 1) {
978 neg = 1;
979 left--, p++;
980 }
981 if (*p < '' || *p > '9')
982 break;
983 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
984 len = p-buf;
985 if ((len < left) && *p && !isspace(*p))
986 break;
987 if (neg)
988 val = -val;
989 buffer += len;
990 left -= len;
991
992 if(neg)
993 continue;
994 if (min && val < *min++)
995 continue;
996 if (max && val > *max++)
997 continue;
998 *i = val;
999 } else {
1000 p = buf;
1001 if (!first)
1002 *p++ = '\t';
1003 sprintf(p, "%lu", convdiv * (*i) / convmul);
1004 len = strlen(buf);
1005 if (len > left)
1006 len = left;
1007 if(copy_to_user(buffer, buf, len))
1008 return -EFAULT;
1009 left -= len;
1010 buffer += len;
1011 }
1012 }
1013
1014 if (!write && !first && left) {
1015 if(put_user('\n', (char *) buffer))
1016 return -EFAULT;
1017 left--, buffer++;
1018 }
1019 if (write) {
1020 p = (char *) buffer;
1021 while (left) {
1022 char c;
1023 if(get_user(c, p++))
1024 return -EFAULT;
1025 if (!isspace(c))
1026 break;
1027 left--;
1028 }
1029 }
1030 if (write && first)
1031 return -EINVAL;
1032 *lenp -= left;
1033 filp->f_pos += *lenp;
1034 return 0;
1035 #undef TMPBUFLEN
1036 }
1037
1038 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1039 void *buffer, size_t *lenp)
1040 {
1041 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1042 }
1043
1044 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1045 struct file *filp,
1046 void *buffer, size_t *lenp)
1047 {
1048 return do_proc_doulongvec_minmax(table, write, filp, buffer,
1049 lenp, HZ, 1000l);
1050 }
1051
1052
1053 /* Like proc_dointvec, but converts seconds to jiffies */
1054 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1055 void *buffer, size_t *lenp)
1056 {
1057 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1058 }
1059
1060 #else /* CONFIG_PROC_FS */
1061
1062 int proc_dostring(ctl_table *table, int write, struct file *filp,
1063 void *buffer, size_t *lenp)
1064 {
1065 return -ENOSYS;
1066 }
1067
1068 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1069 void *buffer, size_t *lenp)
1070 {
1071 return -ENOSYS;
1072 }
1073
1074 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1075 void *buffer, size_t *lenp)
1076 {
1077 return -ENOSYS;
1078 }
1079
1080 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1081 void *buffer, size_t *lenp)
1082 {
1083 return -ENOSYS;
1084 }
1085
1086 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1087 void *buffer, size_t *lenp)
1088 {
1089 return -ENOSYS;
1090 }
1091
1092 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1093 void *buffer, size_t *lenp)
1094 {
1095 return -ENOSYS;
1096 }
1097
1098 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1099 void *buffer, size_t *lenp)
1100 {
1101 return -ENOSYS;
1102 }
1103
1104 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1105 struct file *filp,
1106 void *buffer, size_t *lenp)
1107 {
1108 return -ENOSYS;
1109 }
1110
1111
1112 #endif /* CONFIG_PROC_FS */
1113
1114
1115 /*
1116 * General sysctl support routines
1117 */
1118
1119 /* The generic string strategy routine: */
1120 int sysctl_string(ctl_table *table, int *name, int nlen,
1121 void *oldval, size_t *oldlenp,
1122 void *newval, size_t newlen, void **context)
1123 {
1124 int l, len;
1125
1126 if (!table->data || !table->maxlen)
1127 return -ENOTDIR;
1128
1129 if (oldval && oldlenp) {
1130 if(get_user(len, oldlenp))
1131 return -EFAULT;
1132 if (len) {
1133 l = strlen(table->data);
1134 if (len > l) len = l;
1135 if (len >= table->maxlen)
1136 len = table->maxlen;
1137 if(copy_to_user(oldval, table->data, len))
1138 return -EFAULT;
1139 if(put_user(0, ((char *) oldval) + len))
1140 return -EFAULT;
1141 if(put_user(len, oldlenp))
1142 return -EFAULT;
1143 }
1144 }
1145 if (newval && newlen) {
1146 len = newlen;
1147 if (len > table->maxlen)
1148 len = table->maxlen;
1149 if(copy_from_user(table->data, newval, len))
1150 return -EFAULT;
1151 if (len == table->maxlen)
1152 len--;
1153 ((char *) table->data)[len] = 0;
1154 }
1155 return 0;
1156 }
1157
1158 /*
1159 * This function makes sure that all of the integers in the vector
1160 * are between the minimum and maximum values given in the arrays
1161 * table->extra1 and table->extra2, respectively.
1162 */
1163 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1164 void *oldval, size_t *oldlenp,
1165 void *newval, size_t newlen, void **context)
1166 {
1167 int i, length, *vec, *min, *max;
1168
1169 if (newval && newlen) {
1170 if (newlen % sizeof(int) != 0)
1171 return -EINVAL;
1172
1173 if (!table->extra1 && !table->extra2)
1174 return 0;
1175
1176 if (newlen > table->maxlen)
1177 newlen = table->maxlen;
1178 length = newlen / sizeof(int);
1179
1180 vec = (int *) newval;
1181 min = (int *) table->extra1;
1182 max = (int *) table->extra2;
1183
1184 for (i = 0; i < length; i++) {
1185 int value;
1186 get_user(value, vec + i);
1187 if (min && value < min[i])
1188 return -EINVAL;
1189 if (max && value > max[i])
1190 return -EINVAL;
1191 }
1192 }
1193 return 0;
1194 }
1195
1196 /* Strategy function to convert jiffies to seconds */
1197 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1198 void *oldval, size_t *oldlenp,
1199 void *newval, size_t newlen, void **context)
1200 {
1201 if (oldval) {
1202 size_t olen;
1203 if (oldlenp) {
1204 if (get_user(olen, oldlenp))
1205 return -EFAULT;
1206 if (olen!=sizeof(int))
1207 return -EINVAL;
1208 }
1209 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1210 (oldlenp && put_user(sizeof(int),oldlenp)))
1211 return -EFAULT;
1212 }
1213 if (newval && newlen) {
1214 int new;
1215 if (newlen != sizeof(int))
1216 return -EINVAL;
1217 if (get_user(new, (int *)newval))
1218 return -EFAULT;
1219 *(int *)(table->data) = new*HZ;
1220 }
1221 return 1;
1222 }
1223
1224 int do_string (
1225 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1226 int rdwr, char *data, size_t max)
1227 {
1228 int l = strlen(data) + 1;
1229 if (newval && !rdwr)
1230 return -EPERM;
1231 if (newval && newlen >= max)
1232 return -EINVAL;
1233 if (oldval) {
1234 int old_l;
1235 if(get_user(old_l, oldlenp))
1236 return -EFAULT;
1237 if (l > old_l)
1238 return -ENOMEM;
1239 if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
1240 return -EFAULT;
1241 }
1242 if (newval) {
1243 if(copy_from_user(data, newval, newlen))
1244 return -EFAULT;
1245 data[newlen] = 0;
1246 }
1247 return 0;
1248 }
1249
1250 int do_int (
1251 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1252 int rdwr, int *data)
1253 {
1254 if (newval && !rdwr)
1255 return -EPERM;
1256 if (newval && newlen != sizeof(int))
1257 return -EINVAL;
1258 if (oldval) {
1259 int old_l;
1260 if(get_user(old_l, oldlenp))
1261 return -EFAULT;
1262 if (old_l < sizeof(int))
1263 return -ENOMEM;
1264 if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
1265 return -EFAULT;
1266 }
1267 if (newval)
1268 if(copy_from_user(data, newval, sizeof(int)))
1269 return -EFAULT;
1270 return 0;
1271 }
1272
1273 int do_struct (
1274 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1275 int rdwr, void *data, size_t len)
1276 {
1277 if (newval && !rdwr)
1278 return -EPERM;
1279 if (newval && newlen != len)
1280 return -EINVAL;
1281 if (oldval) {
1282 int old_l;
1283 if(get_user(old_l, oldlenp))
1284 return -EFAULT;
1285 if (old_l < len)
1286 return -ENOMEM;
1287 if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
1288 return -EFAULT;
1289 }
1290 if (newval)
1291 if(copy_from_user(data, newval, len))
1292 return -EFAULT;
1293 return 0;
1294 }
1295
1296
1297 #else /* CONFIG_SYSCTL */
1298
1299
1300 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1301 {
1302 return -ENOSYS;
1303 }
1304
1305 int sysctl_string(ctl_table *table, int *name, int nlen,
1306 void *oldval, size_t *oldlenp,
1307 void *newval, size_t newlen, void **context)
1308 {
1309 return -ENOSYS;
1310 }
1311
1312 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1313 void *oldval, size_t *oldlenp,
1314 void *newval, size_t newlen, void **context)
1315 {
1316 return -ENOSYS;
1317 }
1318
1319 int proc_dostring(ctl_table *table, int write, struct file *filp,
1320 void *buffer, size_t *lenp)
1321 {
1322 return -ENOSYS;
1323 }
1324
1325 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1326 void *buffer, size_t *lenp)
1327 {
1328 return -ENOSYS;
1329 }
1330
1331 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1332 void *buffer, size_t *lenp)
1333 {
1334 return -ENOSYS;
1335 }
1336
1337 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1338 void *buffer, size_t *lenp)
1339 {
1340 return -ENOSYS;
1341 }
1342
1343 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1344 void *buffer, size_t *lenp)
1345 {
1346 return -ENOSYS;
1347 }
1348
1349 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1350 void *buffer, size_t *lenp)
1351 {
1352 return -ENOSYS;
1353 }
1354
1355 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1356 struct file *filp,
1357 void *buffer, size_t *lenp)
1358 {
1359 return -ENOSYS;
1360 }
1361
1362 struct ctl_table_header * register_sysctl_table(ctl_table * table,
1363 int insert_at_head)
1364 {
1365 return 0;
1366 }
1367
1368 void unregister_sysctl_table(struct ctl_table_header * table)
1369 {
1370 }
1371
1372 #endif /* CONFIG_SYSCTL */
1373
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.