diff options
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 2337 |
1 files changed, 2337 insertions, 0 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c new file mode 100644 index 000000000000..79dbd93bd697 --- /dev/null +++ b/kernel/sysctl.c | |||
@@ -0,0 +1,2337 @@ | |||
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 | * Changed linked lists to use list.h instead of lists.h, 02/24/00, Bill | ||
16 | * Wendling. | ||
17 | * The list_for_each() macro wasn't appropriate for the sysctl loop. | ||
18 | * Removed it and replaced it with older style, 03/23/00, Bill Wendling | ||
19 | */ | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/swap.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/sysctl.h> | ||
27 | #include <linux/proc_fs.h> | ||
28 | #include <linux/ctype.h> | ||
29 | #include <linux/utsname.h> | ||
30 | #include <linux/capability.h> | ||
31 | #include <linux/smp_lock.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/sysrq.h> | ||
35 | #include <linux/highuid.h> | ||
36 | #include <linux/writeback.h> | ||
37 | #include <linux/hugetlb.h> | ||
38 | #include <linux/security.h> | ||
39 | #include <linux/initrd.h> | ||
40 | #include <linux/times.h> | ||
41 | #include <linux/limits.h> | ||
42 | #include <linux/dcache.h> | ||
43 | #include <linux/syscalls.h> | ||
44 | |||
45 | #include <asm/uaccess.h> | ||
46 | #include <asm/processor.h> | ||
47 | |||
48 | #ifdef CONFIG_ROOT_NFS | ||
49 | #include <linux/nfs_fs.h> | ||
50 | #endif | ||
51 | |||
52 | #if defined(CONFIG_SYSCTL) | ||
53 | |||
54 | /* External variables not in a header file. */ | ||
55 | extern int C_A_D; | ||
56 | extern int sysctl_overcommit_memory; | ||
57 | extern int sysctl_overcommit_ratio; | ||
58 | extern int max_threads; | ||
59 | extern int sysrq_enabled; | ||
60 | extern int core_uses_pid; | ||
61 | extern char core_pattern[]; | ||
62 | extern int cad_pid; | ||
63 | extern int pid_max; | ||
64 | extern int min_free_kbytes; | ||
65 | extern int printk_ratelimit_jiffies; | ||
66 | extern int printk_ratelimit_burst; | ||
67 | extern int pid_max_min, pid_max_max; | ||
68 | |||
69 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) | ||
70 | int unknown_nmi_panic; | ||
71 | extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *, | ||
72 | void __user *, size_t *, loff_t *); | ||
73 | #endif | ||
74 | |||
75 | /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ | ||
76 | static int maxolduid = 65535; | ||
77 | static int minolduid; | ||
78 | |||
79 | static int ngroups_max = NGROUPS_MAX; | ||
80 | |||
81 | #ifdef CONFIG_KMOD | ||
82 | extern char modprobe_path[]; | ||
83 | #endif | ||
84 | #ifdef CONFIG_HOTPLUG | ||
85 | extern char hotplug_path[]; | ||
86 | #endif | ||
87 | #ifdef CONFIG_CHR_DEV_SG | ||
88 | extern int sg_big_buff; | ||
89 | #endif | ||
90 | #ifdef CONFIG_SYSVIPC | ||
91 | extern size_t shm_ctlmax; | ||
92 | extern size_t shm_ctlall; | ||
93 | extern int shm_ctlmni; | ||
94 | extern int msg_ctlmax; | ||
95 | extern int msg_ctlmnb; | ||
96 | extern int msg_ctlmni; | ||
97 | extern int sem_ctls[]; | ||
98 | #endif | ||
99 | |||
100 | #ifdef __sparc__ | ||
101 | extern char reboot_command []; | ||
102 | extern int stop_a_enabled; | ||
103 | extern int scons_pwroff; | ||
104 | #endif | ||
105 | |||
106 | #ifdef __hppa__ | ||
107 | extern int pwrsw_enabled; | ||
108 | extern int unaligned_enabled; | ||
109 | #endif | ||
110 | |||
111 | #ifdef CONFIG_ARCH_S390 | ||
112 | #ifdef CONFIG_MATHEMU | ||
113 | extern int sysctl_ieee_emulation_warnings; | ||
114 | #endif | ||
115 | extern int sysctl_userprocess_debug; | ||
116 | #endif | ||
117 | |||
118 | extern int sysctl_hz_timer; | ||
119 | |||
120 | #ifdef CONFIG_BSD_PROCESS_ACCT | ||
121 | extern int acct_parm[]; | ||
122 | #endif | ||
123 | |||
124 | int randomize_va_space = 1; | ||
125 | |||
126 | static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t, | ||
127 | ctl_table *, void **); | ||
128 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | ||
129 | void __user *buffer, size_t *lenp, loff_t *ppos); | ||
130 | |||
131 | static ctl_table root_table[]; | ||
132 | static struct ctl_table_header root_table_header = | ||
133 | { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) }; | ||
134 | |||
135 | static ctl_table kern_table[]; | ||
136 | static ctl_table vm_table[]; | ||
137 | #ifdef CONFIG_NET | ||
138 | extern ctl_table net_table[]; | ||
139 | #endif | ||
140 | static ctl_table proc_table[]; | ||
141 | static ctl_table fs_table[]; | ||
142 | static ctl_table debug_table[]; | ||
143 | static ctl_table dev_table[]; | ||
144 | extern ctl_table random_table[]; | ||
145 | #ifdef CONFIG_UNIX98_PTYS | ||
146 | extern ctl_table pty_table[]; | ||
147 | #endif | ||
148 | |||
149 | #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT | ||
150 | int sysctl_legacy_va_layout; | ||
151 | #endif | ||
152 | |||
153 | /* /proc declarations: */ | ||
154 | |||
155 | #ifdef CONFIG_PROC_FS | ||
156 | |||
157 | static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *); | ||
158 | static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *); | ||
159 | static int proc_opensys(struct inode *, struct file *); | ||
160 | |||
161 | struct file_operations proc_sys_file_operations = { | ||
162 | .open = proc_opensys, | ||
163 | .read = proc_readsys, | ||
164 | .write = proc_writesys, | ||
165 | }; | ||
166 | |||
167 | extern struct proc_dir_entry *proc_sys_root; | ||
168 | |||
169 | static void register_proc_table(ctl_table *, struct proc_dir_entry *); | ||
170 | static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); | ||
171 | #endif | ||
172 | |||
173 | /* The default sysctl tables: */ | ||
174 | |||
175 | static ctl_table root_table[] = { | ||
176 | { | ||
177 | .ctl_name = CTL_KERN, | ||
178 | .procname = "kernel", | ||
179 | .mode = 0555, | ||
180 | .child = kern_table, | ||
181 | }, | ||
182 | { | ||
183 | .ctl_name = CTL_VM, | ||
184 | .procname = "vm", | ||
185 | .mode = 0555, | ||
186 | .child = vm_table, | ||
187 | }, | ||
188 | #ifdef CONFIG_NET | ||
189 | { | ||
190 | .ctl_name = CTL_NET, | ||
191 | .procname = "net", | ||
192 | .mode = 0555, | ||
193 | .child = net_table, | ||
194 | }, | ||
195 | #endif | ||
196 | { | ||
197 | .ctl_name = CTL_PROC, | ||
198 | .procname = "proc", | ||
199 | .mode = 0555, | ||
200 | .child = proc_table, | ||
201 | }, | ||
202 | { | ||
203 | .ctl_name = CTL_FS, | ||
204 | .procname = "fs", | ||
205 | .mode = 0555, | ||
206 | .child = fs_table, | ||
207 | }, | ||
208 | { | ||
209 | .ctl_name = CTL_DEBUG, | ||
210 | .procname = "debug", | ||
211 | .mode = 0555, | ||
212 | .child = debug_table, | ||
213 | }, | ||
214 | { | ||
215 | .ctl_name = CTL_DEV, | ||
216 | .procname = "dev", | ||
217 | .mode = 0555, | ||
218 | .child = dev_table, | ||
219 | }, | ||
220 | { .ctl_name = 0 } | ||
221 | }; | ||
222 | |||
223 | static ctl_table kern_table[] = { | ||
224 | { | ||
225 | .ctl_name = KERN_OSTYPE, | ||
226 | .procname = "ostype", | ||
227 | .data = system_utsname.sysname, | ||
228 | .maxlen = sizeof(system_utsname.sysname), | ||
229 | .mode = 0444, | ||
230 | .proc_handler = &proc_doutsstring, | ||
231 | .strategy = &sysctl_string, | ||
232 | }, | ||
233 | { | ||
234 | .ctl_name = KERN_OSRELEASE, | ||
235 | .procname = "osrelease", | ||
236 | .data = system_utsname.release, | ||
237 | .maxlen = sizeof(system_utsname.release), | ||
238 | .mode = 0444, | ||
239 | .proc_handler = &proc_doutsstring, | ||
240 | .strategy = &sysctl_string, | ||
241 | }, | ||
242 | { | ||
243 | .ctl_name = KERN_VERSION, | ||
244 | .procname = "version", | ||
245 | .data = system_utsname.version, | ||
246 | .maxlen = sizeof(system_utsname.version), | ||
247 | .mode = 0444, | ||
248 | .proc_handler = &proc_doutsstring, | ||
249 | .strategy = &sysctl_string, | ||
250 | }, | ||
251 | { | ||
252 | .ctl_name = KERN_NODENAME, | ||
253 | .procname = "hostname", | ||
254 | .data = system_utsname.nodename, | ||
255 | .maxlen = sizeof(system_utsname.nodename), | ||
256 | .mode = 0644, | ||
257 | .proc_handler = &proc_doutsstring, | ||
258 | .strategy = &sysctl_string, | ||
259 | }, | ||
260 | { | ||
261 | .ctl_name = KERN_DOMAINNAME, | ||
262 | .procname = "domainname", | ||
263 | .data = system_utsname.domainname, | ||
264 | .maxlen = sizeof(system_utsname.domainname), | ||
265 | .mode = 0644, | ||
266 | .proc_handler = &proc_doutsstring, | ||
267 | .strategy = &sysctl_string, | ||
268 | }, | ||
269 | { | ||
270 | .ctl_name = KERN_PANIC, | ||
271 | .procname = "panic", | ||
272 | .data = &panic_timeout, | ||
273 | .maxlen = sizeof(int), | ||
274 | .mode = 0644, | ||
275 | .proc_handler = &proc_dointvec, | ||
276 | }, | ||
277 | { | ||
278 | .ctl_name = KERN_CORE_USES_PID, | ||
279 | .procname = "core_uses_pid", | ||
280 | .data = &core_uses_pid, | ||
281 | .maxlen = sizeof(int), | ||
282 | .mode = 0644, | ||
283 | .proc_handler = &proc_dointvec, | ||
284 | }, | ||
285 | { | ||
286 | .ctl_name = KERN_CORE_PATTERN, | ||
287 | .procname = "core_pattern", | ||
288 | .data = core_pattern, | ||
289 | .maxlen = 64, | ||
290 | .mode = 0644, | ||
291 | .proc_handler = &proc_dostring, | ||
292 | .strategy = &sysctl_string, | ||
293 | }, | ||
294 | { | ||
295 | .ctl_name = KERN_TAINTED, | ||
296 | .procname = "tainted", | ||
297 | .data = &tainted, | ||
298 | .maxlen = sizeof(int), | ||
299 | .mode = 0444, | ||
300 | .proc_handler = &proc_dointvec, | ||
301 | }, | ||
302 | { | ||
303 | .ctl_name = KERN_CAP_BSET, | ||
304 | .procname = "cap-bound", | ||
305 | .data = &cap_bset, | ||
306 | .maxlen = sizeof(kernel_cap_t), | ||
307 | .mode = 0600, | ||
308 | .proc_handler = &proc_dointvec_bset, | ||
309 | }, | ||
310 | #ifdef CONFIG_BLK_DEV_INITRD | ||
311 | { | ||
312 | .ctl_name = KERN_REALROOTDEV, | ||
313 | .procname = "real-root-dev", | ||
314 | .data = &real_root_dev, | ||
315 | .maxlen = sizeof(int), | ||
316 | .mode = 0644, | ||
317 | .proc_handler = &proc_dointvec, | ||
318 | }, | ||
319 | #endif | ||
320 | #ifdef __sparc__ | ||
321 | { | ||
322 | .ctl_name = KERN_SPARC_REBOOT, | ||
323 | .procname = "reboot-cmd", | ||
324 | .data = reboot_command, | ||
325 | .maxlen = 256, | ||
326 | .mode = 0644, | ||
327 | .proc_handler = &proc_dostring, | ||
328 | .strategy = &sysctl_string, | ||
329 | }, | ||
330 | { | ||
331 | .ctl_name = KERN_SPARC_STOP_A, | ||
332 | .procname = "stop-a", | ||
333 | .data = &stop_a_enabled, | ||
334 | .maxlen = sizeof (int), | ||
335 | .mode = 0644, | ||
336 | .proc_handler = &proc_dointvec, | ||
337 | }, | ||
338 | { | ||
339 | .ctl_name = KERN_SPARC_SCONS_PWROFF, | ||
340 | .procname = "scons-poweroff", | ||
341 | .data = &scons_pwroff, | ||
342 | .maxlen = sizeof (int), | ||
343 | .mode = 0644, | ||
344 | .proc_handler = &proc_dointvec, | ||
345 | }, | ||
346 | #endif | ||
347 | #ifdef __hppa__ | ||
348 | { | ||
349 | .ctl_name = KERN_HPPA_PWRSW, | ||
350 | .procname = "soft-power", | ||
351 | .data = &pwrsw_enabled, | ||
352 | .maxlen = sizeof (int), | ||
353 | .mode = 0644, | ||
354 | .proc_handler = &proc_dointvec, | ||
355 | }, | ||
356 | { | ||
357 | .ctl_name = KERN_HPPA_UNALIGNED, | ||
358 | .procname = "unaligned-trap", | ||
359 | .data = &unaligned_enabled, | ||
360 | .maxlen = sizeof (int), | ||
361 | .mode = 0644, | ||
362 | .proc_handler = &proc_dointvec, | ||
363 | }, | ||
364 | #endif | ||
365 | { | ||
366 | .ctl_name = KERN_CTLALTDEL, | ||
367 | .procname = "ctrl-alt-del", | ||
368 | .data = &C_A_D, | ||
369 | .maxlen = sizeof(int), | ||
370 | .mode = 0644, | ||
371 | .proc_handler = &proc_dointvec, | ||
372 | }, | ||
373 | { | ||
374 | .ctl_name = KERN_PRINTK, | ||
375 | .procname = "printk", | ||
376 | .data = &console_loglevel, | ||
377 | .maxlen = 4*sizeof(int), | ||
378 | .mode = 0644, | ||
379 | .proc_handler = &proc_dointvec, | ||
380 | }, | ||
381 | #ifdef CONFIG_KMOD | ||
382 | { | ||
383 | .ctl_name = KERN_MODPROBE, | ||
384 | .procname = "modprobe", | ||
385 | .data = &modprobe_path, | ||
386 | .maxlen = KMOD_PATH_LEN, | ||
387 | .mode = 0644, | ||
388 | .proc_handler = &proc_dostring, | ||
389 | .strategy = &sysctl_string, | ||
390 | }, | ||
391 | #endif | ||
392 | #ifdef CONFIG_HOTPLUG | ||
393 | { | ||
394 | .ctl_name = KERN_HOTPLUG, | ||
395 | .procname = "hotplug", | ||
396 | .data = &hotplug_path, | ||
397 | .maxlen = HOTPLUG_PATH_LEN, | ||
398 | .mode = 0644, | ||
399 | .proc_handler = &proc_dostring, | ||
400 | .strategy = &sysctl_string, | ||
401 | }, | ||
402 | #endif | ||
403 | #ifdef CONFIG_CHR_DEV_SG | ||
404 | { | ||
405 | .ctl_name = KERN_SG_BIG_BUFF, | ||
406 | .procname = "sg-big-buff", | ||
407 | .data = &sg_big_buff, | ||
408 | .maxlen = sizeof (int), | ||
409 | .mode = 0444, | ||
410 | .proc_handler = &proc_dointvec, | ||
411 | }, | ||
412 | #endif | ||
413 | #ifdef CONFIG_BSD_PROCESS_ACCT | ||
414 | { | ||
415 | .ctl_name = KERN_ACCT, | ||
416 | .procname = "acct", | ||
417 | .data = &acct_parm, | ||
418 | .maxlen = 3*sizeof(int), | ||
419 | .mode = 0644, | ||
420 | .proc_handler = &proc_dointvec, | ||
421 | }, | ||
422 | #endif | ||
423 | #ifdef CONFIG_SYSVIPC | ||
424 | { | ||
425 | .ctl_name = KERN_SHMMAX, | ||
426 | .procname = "shmmax", | ||
427 | .data = &shm_ctlmax, | ||
428 | .maxlen = sizeof (size_t), | ||
429 | .mode = 0644, | ||
430 | .proc_handler = &proc_doulongvec_minmax, | ||
431 | }, | ||
432 | { | ||
433 | .ctl_name = KERN_SHMALL, | ||
434 | .procname = "shmall", | ||
435 | .data = &shm_ctlall, | ||
436 | .maxlen = sizeof (size_t), | ||
437 | .mode = 0644, | ||
438 | .proc_handler = &proc_doulongvec_minmax, | ||
439 | }, | ||
440 | { | ||
441 | .ctl_name = KERN_SHMMNI, | ||
442 | .procname = "shmmni", | ||
443 | .data = &shm_ctlmni, | ||
444 | .maxlen = sizeof (int), | ||
445 | .mode = 0644, | ||
446 | .proc_handler = &proc_dointvec, | ||
447 | }, | ||
448 | { | ||
449 | .ctl_name = KERN_MSGMAX, | ||
450 | .procname = "msgmax", | ||
451 | .data = &msg_ctlmax, | ||
452 | .maxlen = sizeof (int), | ||
453 | .mode = 0644, | ||
454 | .proc_handler = &proc_dointvec, | ||
455 | }, | ||
456 | { | ||
457 | .ctl_name = KERN_MSGMNI, | ||
458 | .procname = "msgmni", | ||
459 | .data = &msg_ctlmni, | ||
460 | .maxlen = sizeof (int), | ||
461 | .mode = 0644, | ||
462 | .proc_handler = &proc_dointvec, | ||
463 | }, | ||
464 | { | ||
465 | .ctl_name = KERN_MSGMNB, | ||
466 | .procname = "msgmnb", | ||
467 | .data = &msg_ctlmnb, | ||
468 | .maxlen = sizeof (int), | ||
469 | .mode = 0644, | ||
470 | .proc_handler = &proc_dointvec, | ||
471 | }, | ||
472 | { | ||
473 | .ctl_name = KERN_SEM, | ||
474 | .procname = "sem", | ||
475 | .data = &sem_ctls, | ||
476 | .maxlen = 4*sizeof (int), | ||
477 | .mode = 0644, | ||
478 | .proc_handler = &proc_dointvec, | ||
479 | }, | ||
480 | #endif | ||
481 | #ifdef CONFIG_MAGIC_SYSRQ | ||
482 | { | ||
483 | .ctl_name = KERN_SYSRQ, | ||
484 | .procname = "sysrq", | ||
485 | .data = &sysrq_enabled, | ||
486 | .maxlen = sizeof (int), | ||
487 | .mode = 0644, | ||
488 | .proc_handler = &proc_dointvec, | ||
489 | }, | ||
490 | #endif | ||
491 | { | ||
492 | .ctl_name = KERN_CADPID, | ||
493 | .procname = "cad_pid", | ||
494 | .data = &cad_pid, | ||
495 | .maxlen = sizeof (int), | ||
496 | .mode = 0600, | ||
497 | .proc_handler = &proc_dointvec, | ||
498 | }, | ||
499 | { | ||
500 | .ctl_name = KERN_MAX_THREADS, | ||
501 | .procname = "threads-max", | ||
502 | .data = &max_threads, | ||
503 | .maxlen = sizeof(int), | ||
504 | .mode = 0644, | ||
505 | .proc_handler = &proc_dointvec, | ||
506 | }, | ||
507 | { | ||
508 | .ctl_name = KERN_RANDOM, | ||
509 | .procname = "random", | ||
510 | .mode = 0555, | ||
511 | .child = random_table, | ||
512 | }, | ||
513 | #ifdef CONFIG_UNIX98_PTYS | ||
514 | { | ||
515 | .ctl_name = KERN_PTY, | ||
516 | .procname = "pty", | ||
517 | .mode = 0555, | ||
518 | .child = pty_table, | ||
519 | }, | ||
520 | #endif | ||
521 | { | ||
522 | .ctl_name = KERN_OVERFLOWUID, | ||
523 | .procname = "overflowuid", | ||
524 | .data = &overflowuid, | ||
525 | .maxlen = sizeof(int), | ||
526 | .mode = 0644, | ||
527 | .proc_handler = &proc_dointvec_minmax, | ||
528 | .strategy = &sysctl_intvec, | ||
529 | .extra1 = &minolduid, | ||
530 | .extra2 = &maxolduid, | ||
531 | }, | ||
532 | { | ||
533 | .ctl_name = KERN_OVERFLOWGID, | ||
534 | .procname = "overflowgid", | ||
535 | .data = &overflowgid, | ||
536 | .maxlen = sizeof(int), | ||
537 | .mode = 0644, | ||
538 | .proc_handler = &proc_dointvec_minmax, | ||
539 | .strategy = &sysctl_intvec, | ||
540 | .extra1 = &minolduid, | ||
541 | .extra2 = &maxolduid, | ||
542 | }, | ||
543 | #ifdef CONFIG_ARCH_S390 | ||
544 | #ifdef CONFIG_MATHEMU | ||
545 | { | ||
546 | .ctl_name = KERN_IEEE_EMULATION_WARNINGS, | ||
547 | .procname = "ieee_emulation_warnings", | ||
548 | .data = &sysctl_ieee_emulation_warnings, | ||
549 | .maxlen = sizeof(int), | ||
550 | .mode = 0644, | ||
551 | .proc_handler = &proc_dointvec, | ||
552 | }, | ||
553 | #endif | ||
554 | #ifdef CONFIG_NO_IDLE_HZ | ||
555 | { | ||
556 | .ctl_name = KERN_HZ_TIMER, | ||
557 | .procname = "hz_timer", | ||
558 | .data = &sysctl_hz_timer, | ||
559 | .maxlen = sizeof(int), | ||
560 | .mode = 0644, | ||
561 | .proc_handler = &proc_dointvec, | ||
562 | }, | ||
563 | #endif | ||
564 | { | ||
565 | .ctl_name = KERN_S390_USER_DEBUG_LOGGING, | ||
566 | .procname = "userprocess_debug", | ||
567 | .data = &sysctl_userprocess_debug, | ||
568 | .maxlen = sizeof(int), | ||
569 | .mode = 0644, | ||
570 | .proc_handler = &proc_dointvec, | ||
571 | }, | ||
572 | #endif | ||
573 | { | ||
574 | .ctl_name = KERN_PIDMAX, | ||
575 | .procname = "pid_max", | ||
576 | .data = &pid_max, | ||
577 | .maxlen = sizeof (int), | ||
578 | .mode = 0644, | ||
579 | .proc_handler = &proc_dointvec_minmax, | ||
580 | .strategy = sysctl_intvec, | ||
581 | .extra1 = &pid_max_min, | ||
582 | .extra2 = &pid_max_max, | ||
583 | }, | ||
584 | { | ||
585 | .ctl_name = KERN_PANIC_ON_OOPS, | ||
586 | .procname = "panic_on_oops", | ||
587 | .data = &panic_on_oops, | ||
588 | .maxlen = sizeof(int), | ||
589 | .mode = 0644, | ||
590 | .proc_handler = &proc_dointvec, | ||
591 | }, | ||
592 | { | ||
593 | .ctl_name = KERN_PRINTK_RATELIMIT, | ||
594 | .procname = "printk_ratelimit", | ||
595 | .data = &printk_ratelimit_jiffies, | ||
596 | .maxlen = sizeof(int), | ||
597 | .mode = 0644, | ||
598 | .proc_handler = &proc_dointvec_jiffies, | ||
599 | .strategy = &sysctl_jiffies, | ||
600 | }, | ||
601 | { | ||
602 | .ctl_name = KERN_PRINTK_RATELIMIT_BURST, | ||
603 | .procname = "printk_ratelimit_burst", | ||
604 | .data = &printk_ratelimit_burst, | ||
605 | .maxlen = sizeof(int), | ||
606 | .mode = 0644, | ||
607 | .proc_handler = &proc_dointvec, | ||
608 | }, | ||
609 | { | ||
610 | .ctl_name = KERN_NGROUPS_MAX, | ||
611 | .procname = "ngroups_max", | ||
612 | .data = &ngroups_max, | ||
613 | .maxlen = sizeof (int), | ||
614 | .mode = 0444, | ||
615 | .proc_handler = &proc_dointvec, | ||
616 | }, | ||
617 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) | ||
618 | { | ||
619 | .ctl_name = KERN_UNKNOWN_NMI_PANIC, | ||
620 | .procname = "unknown_nmi_panic", | ||
621 | .data = &unknown_nmi_panic, | ||
622 | .maxlen = sizeof (int), | ||
623 | .mode = 0644, | ||
624 | .proc_handler = &proc_unknown_nmi_panic, | ||
625 | }, | ||
626 | #endif | ||
627 | #if defined(CONFIG_X86) | ||
628 | { | ||
629 | .ctl_name = KERN_BOOTLOADER_TYPE, | ||
630 | .procname = "bootloader_type", | ||
631 | .data = &bootloader_type, | ||
632 | .maxlen = sizeof (int), | ||
633 | .mode = 0444, | ||
634 | .proc_handler = &proc_dointvec, | ||
635 | }, | ||
636 | #endif | ||
637 | { | ||
638 | .ctl_name = KERN_RANDOMIZE, | ||
639 | .procname = "randomize_va_space", | ||
640 | .data = &randomize_va_space, | ||
641 | .maxlen = sizeof(int), | ||
642 | .mode = 0644, | ||
643 | .proc_handler = &proc_dointvec, | ||
644 | }, | ||
645 | |||
646 | { .ctl_name = 0 } | ||
647 | }; | ||
648 | |||
649 | /* Constants for minimum and maximum testing in vm_table. | ||
650 | We use these as one-element integer vectors. */ | ||
651 | static int zero; | ||
652 | static int one_hundred = 100; | ||
653 | |||
654 | |||
655 | static ctl_table vm_table[] = { | ||
656 | { | ||
657 | .ctl_name = VM_OVERCOMMIT_MEMORY, | ||
658 | .procname = "overcommit_memory", | ||
659 | .data = &sysctl_overcommit_memory, | ||
660 | .maxlen = sizeof(sysctl_overcommit_memory), | ||
661 | .mode = 0644, | ||
662 | .proc_handler = &proc_dointvec, | ||
663 | }, | ||
664 | { | ||
665 | .ctl_name = VM_OVERCOMMIT_RATIO, | ||
666 | .procname = "overcommit_ratio", | ||
667 | .data = &sysctl_overcommit_ratio, | ||
668 | .maxlen = sizeof(sysctl_overcommit_ratio), | ||
669 | .mode = 0644, | ||
670 | .proc_handler = &proc_dointvec, | ||
671 | }, | ||
672 | { | ||
673 | .ctl_name = VM_PAGE_CLUSTER, | ||
674 | .procname = "page-cluster", | ||
675 | .data = &page_cluster, | ||
676 | .maxlen = sizeof(int), | ||
677 | .mode = 0644, | ||
678 | .proc_handler = &proc_dointvec, | ||
679 | }, | ||
680 | { | ||
681 | .ctl_name = VM_DIRTY_BACKGROUND, | ||
682 | .procname = "dirty_background_ratio", | ||
683 | .data = &dirty_background_ratio, | ||
684 | .maxlen = sizeof(dirty_background_ratio), | ||
685 | .mode = 0644, | ||
686 | .proc_handler = &proc_dointvec_minmax, | ||
687 | .strategy = &sysctl_intvec, | ||
688 | .extra1 = &zero, | ||
689 | .extra2 = &one_hundred, | ||
690 | }, | ||
691 | { | ||
692 | .ctl_name = VM_DIRTY_RATIO, | ||
693 | .procname = "dirty_ratio", | ||
694 | .data = &vm_dirty_ratio, | ||
695 | .maxlen = sizeof(vm_dirty_ratio), | ||
696 | .mode = 0644, | ||
697 | .proc_handler = &proc_dointvec_minmax, | ||
698 | .strategy = &sysctl_intvec, | ||
699 | .extra1 = &zero, | ||
700 | .extra2 = &one_hundred, | ||
701 | }, | ||
702 | { | ||
703 | .ctl_name = VM_DIRTY_WB_CS, | ||
704 | .procname = "dirty_writeback_centisecs", | ||
705 | .data = &dirty_writeback_centisecs, | ||
706 | .maxlen = sizeof(dirty_writeback_centisecs), | ||
707 | .mode = 0644, | ||
708 | .proc_handler = &dirty_writeback_centisecs_handler, | ||
709 | }, | ||
710 | { | ||
711 | .ctl_name = VM_DIRTY_EXPIRE_CS, | ||
712 | .procname = "dirty_expire_centisecs", | ||
713 | .data = &dirty_expire_centisecs, | ||
714 | .maxlen = sizeof(dirty_expire_centisecs), | ||
715 | .mode = 0644, | ||
716 | .proc_handler = &proc_dointvec, | ||
717 | }, | ||
718 | { | ||
719 | .ctl_name = VM_NR_PDFLUSH_THREADS, | ||
720 | .procname = "nr_pdflush_threads", | ||
721 | .data = &nr_pdflush_threads, | ||
722 | .maxlen = sizeof nr_pdflush_threads, | ||
723 | .mode = 0444 /* read-only*/, | ||
724 | .proc_handler = &proc_dointvec, | ||
725 | }, | ||
726 | { | ||
727 | .ctl_name = VM_SWAPPINESS, | ||
728 | .procname = "swappiness", | ||
729 | .data = &vm_swappiness, | ||
730 | .maxlen = sizeof(vm_swappiness), | ||
731 | .mode = 0644, | ||
732 | .proc_handler = &proc_dointvec_minmax, | ||
733 | .strategy = &sysctl_intvec, | ||
734 | .extra1 = &zero, | ||
735 | .extra2 = &one_hundred, | ||
736 | }, | ||
737 | #ifdef CONFIG_HUGETLB_PAGE | ||
738 | { | ||
739 | .ctl_name = VM_HUGETLB_PAGES, | ||
740 | .procname = "nr_hugepages", | ||
741 | .data = &max_huge_pages, | ||
742 | .maxlen = sizeof(unsigned long), | ||
743 | .mode = 0644, | ||
744 | .proc_handler = &hugetlb_sysctl_handler, | ||
745 | .extra1 = (void *)&hugetlb_zero, | ||
746 | .extra2 = (void *)&hugetlb_infinity, | ||
747 | }, | ||
748 | { | ||
749 | .ctl_name = VM_HUGETLB_GROUP, | ||
750 | .procname = "hugetlb_shm_group", | ||
751 | .data = &sysctl_hugetlb_shm_group, | ||
752 | .maxlen = sizeof(gid_t), | ||
753 | .mode = 0644, | ||
754 | .proc_handler = &proc_dointvec, | ||
755 | }, | ||
756 | #endif | ||
757 | { | ||
758 | .ctl_name = VM_LOWMEM_RESERVE_RATIO, | ||
759 | .procname = "lowmem_reserve_ratio", | ||
760 | .data = &sysctl_lowmem_reserve_ratio, | ||
761 | .maxlen = sizeof(sysctl_lowmem_reserve_ratio), | ||
762 | .mode = 0644, | ||
763 | .proc_handler = &lowmem_reserve_ratio_sysctl_handler, | ||
764 | .strategy = &sysctl_intvec, | ||
765 | }, | ||
766 | { | ||
767 | .ctl_name = VM_MIN_FREE_KBYTES, | ||
768 | .procname = "min_free_kbytes", | ||
769 | .data = &min_free_kbytes, | ||
770 | .maxlen = sizeof(min_free_kbytes), | ||
771 | .mode = 0644, | ||
772 | .proc_handler = &min_free_kbytes_sysctl_handler, | ||
773 | .strategy = &sysctl_intvec, | ||
774 | .extra1 = &zero, | ||
775 | }, | ||
776 | #ifdef CONFIG_MMU | ||
777 | { | ||
778 | .ctl_name = VM_MAX_MAP_COUNT, | ||
779 | .procname = "max_map_count", | ||
780 | .data = &sysctl_max_map_count, | ||
781 | .maxlen = sizeof(sysctl_max_map_count), | ||
782 | .mode = 0644, | ||
783 | .proc_handler = &proc_dointvec | ||
784 | }, | ||
785 | #endif | ||
786 | { | ||
787 | .ctl_name = VM_LAPTOP_MODE, | ||
788 | .procname = "laptop_mode", | ||
789 | .data = &laptop_mode, | ||
790 | .maxlen = sizeof(laptop_mode), | ||
791 | .mode = 0644, | ||
792 | .proc_handler = &proc_dointvec, | ||
793 | .strategy = &sysctl_intvec, | ||
794 | .extra1 = &zero, | ||
795 | }, | ||
796 | { | ||
797 | .ctl_name = VM_BLOCK_DUMP, | ||
798 | .procname = "block_dump", | ||
799 | .data = &block_dump, | ||
800 | .maxlen = sizeof(block_dump), | ||
801 | .mode = 0644, | ||
802 | .proc_handler = &proc_dointvec, | ||
803 | .strategy = &sysctl_intvec, | ||
804 | .extra1 = &zero, | ||
805 | }, | ||
806 | { | ||
807 | .ctl_name = VM_VFS_CACHE_PRESSURE, | ||
808 | .procname = "vfs_cache_pressure", | ||
809 | .data = &sysctl_vfs_cache_pressure, | ||
810 | .maxlen = sizeof(sysctl_vfs_cache_pressure), | ||
811 | .mode = 0644, | ||
812 | .proc_handler = &proc_dointvec, | ||
813 | .strategy = &sysctl_intvec, | ||
814 | .extra1 = &zero, | ||
815 | }, | ||
816 | #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT | ||
817 | { | ||
818 | .ctl_name = VM_LEGACY_VA_LAYOUT, | ||
819 | .procname = "legacy_va_layout", | ||
820 | .data = &sysctl_legacy_va_layout, | ||
821 | .maxlen = sizeof(sysctl_legacy_va_layout), | ||
822 | .mode = 0644, | ||
823 | .proc_handler = &proc_dointvec, | ||
824 | .strategy = &sysctl_intvec, | ||
825 | .extra1 = &zero, | ||
826 | }, | ||
827 | #endif | ||
828 | #ifdef CONFIG_SWAP | ||
829 | { | ||
830 | .ctl_name = VM_SWAP_TOKEN_TIMEOUT, | ||
831 | .procname = "swap_token_timeout", | ||
832 | .data = &swap_token_default_timeout, | ||
833 | .maxlen = sizeof(swap_token_default_timeout), | ||
834 | .mode = 0644, | ||
835 | .proc_handler = &proc_dointvec_jiffies, | ||
836 | .strategy = &sysctl_jiffies, | ||
837 | }, | ||
838 | #endif | ||
839 | { .ctl_name = 0 } | ||
840 | }; | ||
841 | |||
842 | static ctl_table proc_table[] = { | ||
843 | { .ctl_name = 0 } | ||
844 | }; | ||
845 | |||
846 | static ctl_table fs_table[] = { | ||
847 | { | ||
848 | .ctl_name = FS_NRINODE, | ||
849 | .procname = "inode-nr", | ||
850 | .data = &inodes_stat, | ||
851 | .maxlen = 2*sizeof(int), | ||
852 | .mode = 0444, | ||
853 | .proc_handler = &proc_dointvec, | ||
854 | }, | ||
855 | { | ||
856 | .ctl_name = FS_STATINODE, | ||
857 | .procname = "inode-state", | ||
858 | .data = &inodes_stat, | ||
859 | .maxlen = 7*sizeof(int), | ||
860 | .mode = 0444, | ||
861 | .proc_handler = &proc_dointvec, | ||
862 | }, | ||
863 | { | ||
864 | .ctl_name = FS_NRFILE, | ||
865 | .procname = "file-nr", | ||
866 | .data = &files_stat, | ||
867 | .maxlen = 3*sizeof(int), | ||
868 | .mode = 0444, | ||
869 | .proc_handler = &proc_dointvec, | ||
870 | }, | ||
871 | { | ||
872 | .ctl_name = FS_MAXFILE, | ||
873 | .procname = "file-max", | ||
874 | .data = &files_stat.max_files, | ||
875 | .maxlen = sizeof(int), | ||
876 | .mode = 0644, | ||
877 | .proc_handler = &proc_dointvec, | ||
878 | }, | ||
879 | { | ||
880 | .ctl_name = FS_DENTRY, | ||
881 | .procname = "dentry-state", | ||
882 | .data = &dentry_stat, | ||
883 | .maxlen = 6*sizeof(int), | ||
884 | .mode = 0444, | ||
885 | .proc_handler = &proc_dointvec, | ||
886 | }, | ||
887 | { | ||
888 | .ctl_name = FS_OVERFLOWUID, | ||
889 | .procname = "overflowuid", | ||
890 | .data = &fs_overflowuid, | ||
891 | .maxlen = sizeof(int), | ||
892 | .mode = 0644, | ||
893 | .proc_handler = &proc_dointvec_minmax, | ||
894 | .strategy = &sysctl_intvec, | ||
895 | .extra1 = &minolduid, | ||
896 | .extra2 = &maxolduid, | ||
897 | }, | ||
898 | { | ||
899 | .ctl_name = FS_OVERFLOWGID, | ||
900 | .procname = "overflowgid", | ||
901 | .data = &fs_overflowgid, | ||
902 | .maxlen = sizeof(int), | ||
903 | .mode = 0644, | ||
904 | .proc_handler = &proc_dointvec_minmax, | ||
905 | .strategy = &sysctl_intvec, | ||
906 | .extra1 = &minolduid, | ||
907 | .extra2 = &maxolduid, | ||
908 | }, | ||
909 | { | ||
910 | .ctl_name = FS_LEASES, | ||
911 | .procname = "leases-enable", | ||
912 | .data = &leases_enable, | ||
913 | .maxlen = sizeof(int), | ||
914 | .mode = 0644, | ||
915 | .proc_handler = &proc_dointvec, | ||
916 | }, | ||
917 | #ifdef CONFIG_DNOTIFY | ||
918 | { | ||
919 | .ctl_name = FS_DIR_NOTIFY, | ||
920 | .procname = "dir-notify-enable", | ||
921 | .data = &dir_notify_enable, | ||
922 | .maxlen = sizeof(int), | ||
923 | .mode = 0644, | ||
924 | .proc_handler = &proc_dointvec, | ||
925 | }, | ||
926 | #endif | ||
927 | #ifdef CONFIG_MMU | ||
928 | { | ||
929 | .ctl_name = FS_LEASE_TIME, | ||
930 | .procname = "lease-break-time", | ||
931 | .data = &lease_break_time, | ||
932 | .maxlen = sizeof(int), | ||
933 | .mode = 0644, | ||
934 | .proc_handler = &proc_dointvec, | ||
935 | }, | ||
936 | { | ||
937 | .ctl_name = FS_AIO_NR, | ||
938 | .procname = "aio-nr", | ||
939 | .data = &aio_nr, | ||
940 | .maxlen = sizeof(aio_nr), | ||
941 | .mode = 0444, | ||
942 | .proc_handler = &proc_dointvec, | ||
943 | }, | ||
944 | { | ||
945 | .ctl_name = FS_AIO_MAX_NR, | ||
946 | .procname = "aio-max-nr", | ||
947 | .data = &aio_max_nr, | ||
948 | .maxlen = sizeof(aio_max_nr), | ||
949 | .mode = 0644, | ||
950 | .proc_handler = &proc_dointvec, | ||
951 | }, | ||
952 | #endif | ||
953 | { .ctl_name = 0 } | ||
954 | }; | ||
955 | |||
956 | static ctl_table debug_table[] = { | ||
957 | { .ctl_name = 0 } | ||
958 | }; | ||
959 | |||
960 | static ctl_table dev_table[] = { | ||
961 | { .ctl_name = 0 } | ||
962 | }; | ||
963 | |||
964 | extern void init_irq_proc (void); | ||
965 | |||
966 | void __init sysctl_init(void) | ||
967 | { | ||
968 | #ifdef CONFIG_PROC_FS | ||
969 | register_proc_table(root_table, proc_sys_root); | ||
970 | init_irq_proc(); | ||
971 | #endif | ||
972 | } | ||
973 | |||
974 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | ||
975 | void __user *newval, size_t newlen) | ||
976 | { | ||
977 | struct list_head *tmp; | ||
978 | |||
979 | if (nlen <= 0 || nlen >= CTL_MAXNAME) | ||
980 | return -ENOTDIR; | ||
981 | if (oldval) { | ||
982 | int old_len; | ||
983 | if (!oldlenp || get_user(old_len, oldlenp)) | ||
984 | return -EFAULT; | ||
985 | } | ||
986 | tmp = &root_table_header.ctl_entry; | ||
987 | do { | ||
988 | struct ctl_table_header *head = | ||
989 | list_entry(tmp, struct ctl_table_header, ctl_entry); | ||
990 | void *context = NULL; | ||
991 | int error = parse_table(name, nlen, oldval, oldlenp, | ||
992 | newval, newlen, head->ctl_table, | ||
993 | &context); | ||
994 | if (context) | ||
995 | kfree(context); | ||
996 | if (error != -ENOTDIR) | ||
997 | return error; | ||
998 | tmp = tmp->next; | ||
999 | } while (tmp != &root_table_header.ctl_entry); | ||
1000 | return -ENOTDIR; | ||
1001 | } | ||
1002 | |||
1003 | asmlinkage long sys_sysctl(struct __sysctl_args __user *args) | ||
1004 | { | ||
1005 | struct __sysctl_args tmp; | ||
1006 | int error; | ||
1007 | |||
1008 | if (copy_from_user(&tmp, args, sizeof(tmp))) | ||
1009 | return -EFAULT; | ||
1010 | |||
1011 | lock_kernel(); | ||
1012 | error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, | ||
1013 | tmp.newval, tmp.newlen); | ||
1014 | unlock_kernel(); | ||
1015 | return error; | ||
1016 | } | ||
1017 | |||
1018 | /* | ||
1019 | * ctl_perm does NOT grant the superuser all rights automatically, because | ||
1020 | * some sysctl variables are readonly even to root. | ||
1021 | */ | ||
1022 | |||
1023 | static int test_perm(int mode, int op) | ||
1024 | { | ||
1025 | if (!current->euid) | ||
1026 | mode >>= 6; | ||
1027 | else if (in_egroup_p(0)) | ||
1028 | mode >>= 3; | ||
1029 | if ((mode & op & 0007) == op) | ||
1030 | return 0; | ||
1031 | return -EACCES; | ||
1032 | } | ||
1033 | |||
1034 | static inline int ctl_perm(ctl_table *table, int op) | ||
1035 | { | ||
1036 | int error; | ||
1037 | error = security_sysctl(table, op); | ||
1038 | if (error) | ||
1039 | return error; | ||
1040 | return test_perm(table->mode, op); | ||
1041 | } | ||
1042 | |||
1043 | static int parse_table(int __user *name, int nlen, | ||
1044 | void __user *oldval, size_t __user *oldlenp, | ||
1045 | void __user *newval, size_t newlen, | ||
1046 | ctl_table *table, void **context) | ||
1047 | { | ||
1048 | int n; | ||
1049 | repeat: | ||
1050 | if (!nlen) | ||
1051 | return -ENOTDIR; | ||
1052 | if (get_user(n, name)) | ||
1053 | return -EFAULT; | ||
1054 | for ( ; table->ctl_name; table++) { | ||
1055 | if (n == table->ctl_name || table->ctl_name == CTL_ANY) { | ||
1056 | int error; | ||
1057 | if (table->child) { | ||
1058 | if (ctl_perm(table, 001)) | ||
1059 | return -EPERM; | ||
1060 | if (table->strategy) { | ||
1061 | error = table->strategy( | ||
1062 | table, name, nlen, | ||
1063 | oldval, oldlenp, | ||
1064 | newval, newlen, context); | ||
1065 | if (error) | ||
1066 | return error; | ||
1067 | } | ||
1068 | name++; | ||
1069 | nlen--; | ||
1070 | table = table->child; | ||
1071 | goto repeat; | ||
1072 | } | ||
1073 | error = do_sysctl_strategy(table, name, nlen, | ||
1074 | oldval, oldlenp, | ||
1075 | newval, newlen, context); | ||
1076 | return error; | ||
1077 | } | ||
1078 | } | ||
1079 | return -ENOTDIR; | ||
1080 | } | ||
1081 | |||
1082 | /* Perform the actual read/write of a sysctl table entry. */ | ||
1083 | int do_sysctl_strategy (ctl_table *table, | ||
1084 | int __user *name, int nlen, | ||
1085 | void __user *oldval, size_t __user *oldlenp, | ||
1086 | void __user *newval, size_t newlen, void **context) | ||
1087 | { | ||
1088 | int op = 0, rc; | ||
1089 | size_t len; | ||
1090 | |||
1091 | if (oldval) | ||
1092 | op |= 004; | ||
1093 | if (newval) | ||
1094 | op |= 002; | ||
1095 | if (ctl_perm(table, op)) | ||
1096 | return -EPERM; | ||
1097 | |||
1098 | if (table->strategy) { | ||
1099 | rc = table->strategy(table, name, nlen, oldval, oldlenp, | ||
1100 | newval, newlen, context); | ||
1101 | if (rc < 0) | ||
1102 | return rc; | ||
1103 | if (rc > 0) | ||
1104 | return 0; | ||
1105 | } | ||
1106 | |||
1107 | /* If there is no strategy routine, or if the strategy returns | ||
1108 | * zero, proceed with automatic r/w */ | ||
1109 | if (table->data && table->maxlen) { | ||
1110 | if (oldval && oldlenp) { | ||
1111 | if (get_user(len, oldlenp)) | ||
1112 | return -EFAULT; | ||
1113 | if (len) { | ||
1114 | if (len > table->maxlen) | ||
1115 | len = table->maxlen; | ||
1116 | if(copy_to_user(oldval, table->data, len)) | ||
1117 | return -EFAULT; | ||
1118 | if(put_user(len, oldlenp)) | ||
1119 | return -EFAULT; | ||
1120 | } | ||
1121 | } | ||
1122 | if (newval && newlen) { | ||
1123 | len = newlen; | ||
1124 | if (len > table->maxlen) | ||
1125 | len = table->maxlen; | ||
1126 | if(copy_from_user(table->data, newval, len)) | ||
1127 | return -EFAULT; | ||
1128 | } | ||
1129 | } | ||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | /** | ||
1134 | * register_sysctl_table - register a sysctl hierarchy | ||
1135 | * @table: the top-level table structure | ||
1136 | * @insert_at_head: whether the entry should be inserted in front or at the end | ||
1137 | * | ||
1138 | * Register a sysctl table hierarchy. @table should be a filled in ctl_table | ||
1139 | * array. An entry with a ctl_name of 0 terminates the table. | ||
1140 | * | ||
1141 | * The members of the &ctl_table structure are used as follows: | ||
1142 | * | ||
1143 | * ctl_name - This is the numeric sysctl value used by sysctl(2). The number | ||
1144 | * must be unique within that level of sysctl | ||
1145 | * | ||
1146 | * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not | ||
1147 | * enter a sysctl file | ||
1148 | * | ||
1149 | * data - a pointer to data for use by proc_handler | ||
1150 | * | ||
1151 | * maxlen - the maximum size in bytes of the data | ||
1152 | * | ||
1153 | * mode - the file permissions for the /proc/sys file, and for sysctl(2) | ||
1154 | * | ||
1155 | * child - a pointer to the child sysctl table if this entry is a directory, or | ||
1156 | * %NULL. | ||
1157 | * | ||
1158 | * proc_handler - the text handler routine (described below) | ||
1159 | * | ||
1160 | * strategy - the strategy routine (described below) | ||
1161 | * | ||
1162 | * de - for internal use by the sysctl routines | ||
1163 | * | ||
1164 | * extra1, extra2 - extra pointers usable by the proc handler routines | ||
1165 | * | ||
1166 | * Leaf nodes in the sysctl tree will be represented by a single file | ||
1167 | * under /proc; non-leaf nodes will be represented by directories. | ||
1168 | * | ||
1169 | * sysctl(2) can automatically manage read and write requests through | ||
1170 | * the sysctl table. The data and maxlen fields of the ctl_table | ||
1171 | * struct enable minimal validation of the values being written to be | ||
1172 | * performed, and the mode field allows minimal authentication. | ||
1173 | * | ||
1174 | * More sophisticated management can be enabled by the provision of a | ||
1175 | * strategy routine with the table entry. This will be called before | ||
1176 | * any automatic read or write of the data is performed. | ||
1177 | * | ||
1178 | * The strategy routine may return | ||
1179 | * | ||
1180 | * < 0 - Error occurred (error is passed to user process) | ||
1181 | * | ||
1182 | * 0 - OK - proceed with automatic read or write. | ||
1183 | * | ||
1184 | * > 0 - OK - read or write has been done by the strategy routine, so | ||
1185 | * return immediately. | ||
1186 | * | ||
1187 | * There must be a proc_handler routine for any terminal nodes | ||
1188 | * mirrored under /proc/sys (non-terminals are handled by a built-in | ||
1189 | * directory handler). Several default handlers are available to | ||
1190 | * cover common cases - | ||
1191 | * | ||
1192 | * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(), | ||
1193 | * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(), | ||
1194 | * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax() | ||
1195 | * | ||
1196 | * It is the handler's job to read the input buffer from user memory | ||
1197 | * and process it. The handler should return 0 on success. | ||
1198 | * | ||
1199 | * This routine returns %NULL on a failure to register, and a pointer | ||
1200 | * to the table header on success. | ||
1201 | */ | ||
1202 | struct ctl_table_header *register_sysctl_table(ctl_table * table, | ||
1203 | int insert_at_head) | ||
1204 | { | ||
1205 | struct ctl_table_header *tmp; | ||
1206 | tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL); | ||
1207 | if (!tmp) | ||
1208 | return NULL; | ||
1209 | tmp->ctl_table = table; | ||
1210 | INIT_LIST_HEAD(&tmp->ctl_entry); | ||
1211 | if (insert_at_head) | ||
1212 | list_add(&tmp->ctl_entry, &root_table_header.ctl_entry); | ||
1213 | else | ||
1214 | list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); | ||
1215 | #ifdef CONFIG_PROC_FS | ||
1216 | register_proc_table(table, proc_sys_root); | ||
1217 | #endif | ||
1218 | return tmp; | ||
1219 | } | ||
1220 | |||
1221 | /** | ||
1222 | * unregister_sysctl_table - unregister a sysctl table hierarchy | ||
1223 | * @header: the header returned from register_sysctl_table | ||
1224 | * | ||
1225 | * Unregisters the sysctl table and all children. proc entries may not | ||
1226 | * actually be removed until they are no longer used by anyone. | ||
1227 | */ | ||
1228 | void unregister_sysctl_table(struct ctl_table_header * header) | ||
1229 | { | ||
1230 | list_del(&header->ctl_entry); | ||
1231 | #ifdef CONFIG_PROC_FS | ||
1232 | unregister_proc_table(header->ctl_table, proc_sys_root); | ||
1233 | #endif | ||
1234 | kfree(header); | ||
1235 | } | ||
1236 | |||
1237 | /* | ||
1238 | * /proc/sys support | ||
1239 | */ | ||
1240 | |||
1241 | #ifdef CONFIG_PROC_FS | ||
1242 | |||
1243 | /* Scan the sysctl entries in table and add them all into /proc */ | ||
1244 | static void register_proc_table(ctl_table * table, struct proc_dir_entry *root) | ||
1245 | { | ||
1246 | struct proc_dir_entry *de; | ||
1247 | int len; | ||
1248 | mode_t mode; | ||
1249 | |||
1250 | for (; table->ctl_name; table++) { | ||
1251 | /* Can't do anything without a proc name. */ | ||
1252 | if (!table->procname) | ||
1253 | continue; | ||
1254 | /* Maybe we can't do anything with it... */ | ||
1255 | if (!table->proc_handler && !table->child) { | ||
1256 | printk(KERN_WARNING "SYSCTL: Can't register %s\n", | ||
1257 | table->procname); | ||
1258 | continue; | ||
1259 | } | ||
1260 | |||
1261 | len = strlen(table->procname); | ||
1262 | mode = table->mode; | ||
1263 | |||
1264 | de = NULL; | ||
1265 | if (table->proc_handler) | ||
1266 | mode |= S_IFREG; | ||
1267 | else { | ||
1268 | mode |= S_IFDIR; | ||
1269 | for (de = root->subdir; de; de = de->next) { | ||
1270 | if (proc_match(len, table->procname, de)) | ||
1271 | break; | ||
1272 | } | ||
1273 | /* If the subdir exists already, de is non-NULL */ | ||
1274 | } | ||
1275 | |||
1276 | if (!de) { | ||
1277 | de = create_proc_entry(table->procname, mode, root); | ||
1278 | if (!de) | ||
1279 | continue; | ||
1280 | de->data = (void *) table; | ||
1281 | if (table->proc_handler) | ||
1282 | de->proc_fops = &proc_sys_file_operations; | ||
1283 | } | ||
1284 | table->de = de; | ||
1285 | if (de->mode & S_IFDIR) | ||
1286 | register_proc_table(table->child, de); | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | /* | ||
1291 | * Unregister a /proc sysctl table and any subdirectories. | ||
1292 | */ | ||
1293 | static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) | ||
1294 | { | ||
1295 | struct proc_dir_entry *de; | ||
1296 | for (; table->ctl_name; table++) { | ||
1297 | if (!(de = table->de)) | ||
1298 | continue; | ||
1299 | if (de->mode & S_IFDIR) { | ||
1300 | if (!table->child) { | ||
1301 | printk (KERN_ALERT "Help - malformed sysctl tree on free\n"); | ||
1302 | continue; | ||
1303 | } | ||
1304 | unregister_proc_table(table->child, de); | ||
1305 | |||
1306 | /* Don't unregister directories which still have entries.. */ | ||
1307 | if (de->subdir) | ||
1308 | continue; | ||
1309 | } | ||
1310 | |||
1311 | /* Don't unregister proc entries that are still being used.. */ | ||
1312 | if (atomic_read(&de->count)) | ||
1313 | continue; | ||
1314 | |||
1315 | table->de = NULL; | ||
1316 | remove_proc_entry(table->procname, root); | ||
1317 | } | ||
1318 | } | ||
1319 | |||
1320 | static ssize_t do_rw_proc(int write, struct file * file, char __user * buf, | ||
1321 | size_t count, loff_t *ppos) | ||
1322 | { | ||
1323 | int op; | ||
1324 | struct proc_dir_entry *de; | ||
1325 | struct ctl_table *table; | ||
1326 | size_t res; | ||
1327 | ssize_t error; | ||
1328 | |||
1329 | de = PDE(file->f_dentry->d_inode); | ||
1330 | if (!de || !de->data) | ||
1331 | return -ENOTDIR; | ||
1332 | table = (struct ctl_table *) de->data; | ||
1333 | if (!table || !table->proc_handler) | ||
1334 | return -ENOTDIR; | ||
1335 | op = (write ? 002 : 004); | ||
1336 | if (ctl_perm(table, op)) | ||
1337 | return -EPERM; | ||
1338 | |||
1339 | res = count; | ||
1340 | |||
1341 | error = (*table->proc_handler) (table, write, file, buf, &res, ppos); | ||
1342 | if (error) | ||
1343 | return error; | ||
1344 | return res; | ||
1345 | } | ||
1346 | |||
1347 | static int proc_opensys(struct inode *inode, struct file *file) | ||
1348 | { | ||
1349 | if (file->f_mode & FMODE_WRITE) { | ||
1350 | /* | ||
1351 | * sysctl entries that are not writable, | ||
1352 | * are _NOT_ writable, capabilities or not. | ||
1353 | */ | ||
1354 | if (!(inode->i_mode & S_IWUSR)) | ||
1355 | return -EPERM; | ||
1356 | } | ||
1357 | |||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | static ssize_t proc_readsys(struct file * file, char __user * buf, | ||
1362 | size_t count, loff_t *ppos) | ||
1363 | { | ||
1364 | return do_rw_proc(0, file, buf, count, ppos); | ||
1365 | } | ||
1366 | |||
1367 | static ssize_t proc_writesys(struct file * file, const char __user * buf, | ||
1368 | size_t count, loff_t *ppos) | ||
1369 | { | ||
1370 | return do_rw_proc(1, file, (char __user *) buf, count, ppos); | ||
1371 | } | ||
1372 | |||
1373 | /** | ||
1374 | * proc_dostring - read a string sysctl | ||
1375 | * @table: the sysctl table | ||
1376 | * @write: %TRUE if this is a write to the sysctl file | ||
1377 | * @filp: the file structure | ||
1378 | * @buffer: the user buffer | ||
1379 | * @lenp: the size of the user buffer | ||
1380 | * @ppos: file position | ||
1381 | * | ||
1382 | * Reads/writes a string from/to the user buffer. If the kernel | ||
1383 | * buffer provided is not large enough to hold the string, the | ||
1384 | * string is truncated. The copied string is %NULL-terminated. | ||
1385 | * If the string is being read by the user process, it is copied | ||
1386 | * and a newline '\n' is added. It is truncated if the buffer is | ||
1387 | * not large enough. | ||
1388 | * | ||
1389 | * Returns 0 on success. | ||
1390 | */ | ||
1391 | int proc_dostring(ctl_table *table, int write, struct file *filp, | ||
1392 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1393 | { | ||
1394 | size_t len; | ||
1395 | char __user *p; | ||
1396 | char c; | ||
1397 | |||
1398 | if (!table->data || !table->maxlen || !*lenp || | ||
1399 | (*ppos && !write)) { | ||
1400 | *lenp = 0; | ||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | if (write) { | ||
1405 | len = 0; | ||
1406 | p = buffer; | ||
1407 | while (len < *lenp) { | ||
1408 | if (get_user(c, p++)) | ||
1409 | return -EFAULT; | ||
1410 | if (c == 0 || c == '\n') | ||
1411 | break; | ||
1412 | len++; | ||
1413 | } | ||
1414 | if (len >= table->maxlen) | ||
1415 | len = table->maxlen-1; | ||
1416 | if(copy_from_user(table->data, buffer, len)) | ||
1417 | return -EFAULT; | ||
1418 | ((char *) table->data)[len] = 0; | ||
1419 | *ppos += *lenp; | ||
1420 | } else { | ||
1421 | len = strlen(table->data); | ||
1422 | if (len > table->maxlen) | ||
1423 | len = table->maxlen; | ||
1424 | if (len > *lenp) | ||
1425 | len = *lenp; | ||
1426 | if (len) | ||
1427 | if(copy_to_user(buffer, table->data, len)) | ||
1428 | return -EFAULT; | ||
1429 | if (len < *lenp) { | ||
1430 | if(put_user('\n', ((char __user *) buffer) + len)) | ||
1431 | return -EFAULT; | ||
1432 | len++; | ||
1433 | } | ||
1434 | *lenp = len; | ||
1435 | *ppos += len; | ||
1436 | } | ||
1437 | return 0; | ||
1438 | } | ||
1439 | |||
1440 | /* | ||
1441 | * Special case of dostring for the UTS structure. This has locks | ||
1442 | * to observe. Should this be in kernel/sys.c ???? | ||
1443 | */ | ||
1444 | |||
1445 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | ||
1446 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1447 | { | ||
1448 | int r; | ||
1449 | |||
1450 | if (!write) { | ||
1451 | down_read(&uts_sem); | ||
1452 | r=proc_dostring(table,0,filp,buffer,lenp, ppos); | ||
1453 | up_read(&uts_sem); | ||
1454 | } else { | ||
1455 | down_write(&uts_sem); | ||
1456 | r=proc_dostring(table,1,filp,buffer,lenp, ppos); | ||
1457 | up_write(&uts_sem); | ||
1458 | } | ||
1459 | return r; | ||
1460 | } | ||
1461 | |||
1462 | static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, | ||
1463 | int *valp, | ||
1464 | int write, void *data) | ||
1465 | { | ||
1466 | if (write) { | ||
1467 | *valp = *negp ? -*lvalp : *lvalp; | ||
1468 | } else { | ||
1469 | int val = *valp; | ||
1470 | if (val < 0) { | ||
1471 | *negp = -1; | ||
1472 | *lvalp = (unsigned long)-val; | ||
1473 | } else { | ||
1474 | *negp = 0; | ||
1475 | *lvalp = (unsigned long)val; | ||
1476 | } | ||
1477 | } | ||
1478 | return 0; | ||
1479 | } | ||
1480 | |||
1481 | static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | ||
1482 | void __user *buffer, size_t *lenp, loff_t *ppos, | ||
1483 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, | ||
1484 | int write, void *data), | ||
1485 | void *data) | ||
1486 | { | ||
1487 | #define TMPBUFLEN 21 | ||
1488 | int *i, vleft, first=1, neg, val; | ||
1489 | unsigned long lval; | ||
1490 | size_t left, len; | ||
1491 | |||
1492 | char buf[TMPBUFLEN], *p; | ||
1493 | char __user *s = buffer; | ||
1494 | |||
1495 | if (!table->data || !table->maxlen || !*lenp || | ||
1496 | (*ppos && !write)) { | ||
1497 | *lenp = 0; | ||
1498 | return 0; | ||
1499 | } | ||
1500 | |||
1501 | i = (int *) table->data; | ||
1502 | vleft = table->maxlen / sizeof(*i); | ||
1503 | left = *lenp; | ||
1504 | |||
1505 | if (!conv) | ||
1506 | conv = do_proc_dointvec_conv; | ||
1507 | |||
1508 | for (; left && vleft--; i++, first=0) { | ||
1509 | if (write) { | ||
1510 | while (left) { | ||
1511 | char c; | ||
1512 | if (get_user(c, s)) | ||
1513 | return -EFAULT; | ||
1514 | if (!isspace(c)) | ||
1515 | break; | ||
1516 | left--; | ||
1517 | s++; | ||
1518 | } | ||
1519 | if (!left) | ||
1520 | break; | ||
1521 | neg = 0; | ||
1522 | len = left; | ||
1523 | if (len > sizeof(buf) - 1) | ||
1524 | len = sizeof(buf) - 1; | ||
1525 | if (copy_from_user(buf, s, len)) | ||
1526 | return -EFAULT; | ||
1527 | buf[len] = 0; | ||
1528 | p = buf; | ||
1529 | if (*p == '-' && left > 1) { | ||
1530 | neg = 1; | ||
1531 | left--, p++; | ||
1532 | } | ||
1533 | if (*p < '0' || *p > '9') | ||
1534 | break; | ||
1535 | |||
1536 | lval = simple_strtoul(p, &p, 0); | ||
1537 | |||
1538 | len = p-buf; | ||
1539 | if ((len < left) && *p && !isspace(*p)) | ||
1540 | break; | ||
1541 | if (neg) | ||
1542 | val = -val; | ||
1543 | s += len; | ||
1544 | left -= len; | ||
1545 | |||
1546 | if (conv(&neg, &lval, i, 1, data)) | ||
1547 | break; | ||
1548 | } else { | ||
1549 | p = buf; | ||
1550 | if (!first) | ||
1551 | *p++ = '\t'; | ||
1552 | |||
1553 | if (conv(&neg, &lval, i, 0, data)) | ||
1554 | break; | ||
1555 | |||
1556 | sprintf(p, "%s%lu", neg ? "-" : "", lval); | ||
1557 | len = strlen(buf); | ||
1558 | if (len > left) | ||
1559 | len = left; | ||
1560 | if(copy_to_user(s, buf, len)) | ||
1561 | return -EFAULT; | ||
1562 | left -= len; | ||
1563 | s += len; | ||
1564 | } | ||
1565 | } | ||
1566 | |||
1567 | if (!write && !first && left) { | ||
1568 | if(put_user('\n', s)) | ||
1569 | return -EFAULT; | ||
1570 | left--, s++; | ||
1571 | } | ||
1572 | if (write) { | ||
1573 | while (left) { | ||
1574 | char c; | ||
1575 | if (get_user(c, s++)) | ||
1576 | return -EFAULT; | ||
1577 | if (!isspace(c)) | ||
1578 | break; | ||
1579 | left--; | ||
1580 | } | ||
1581 | } | ||
1582 | if (write && first) | ||
1583 | return -EINVAL; | ||
1584 | *lenp -= left; | ||
1585 | *ppos += *lenp; | ||
1586 | return 0; | ||
1587 | #undef TMPBUFLEN | ||
1588 | } | ||
1589 | |||
1590 | /** | ||
1591 | * proc_dointvec - read a vector of integers | ||
1592 | * @table: the sysctl table | ||
1593 | * @write: %TRUE if this is a write to the sysctl file | ||
1594 | * @filp: the file structure | ||
1595 | * @buffer: the user buffer | ||
1596 | * @lenp: the size of the user buffer | ||
1597 | * @ppos: file position | ||
1598 | * | ||
1599 | * Reads/writes up to table->maxlen/sizeof(unsigned int) integer | ||
1600 | * values from/to the user buffer, treated as an ASCII string. | ||
1601 | * | ||
1602 | * Returns 0 on success. | ||
1603 | */ | ||
1604 | int proc_dointvec(ctl_table *table, int write, struct file *filp, | ||
1605 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1606 | { | ||
1607 | return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, | ||
1608 | NULL,NULL); | ||
1609 | } | ||
1610 | |||
1611 | #define OP_SET 0 | ||
1612 | #define OP_AND 1 | ||
1613 | #define OP_OR 2 | ||
1614 | #define OP_MAX 3 | ||
1615 | #define OP_MIN 4 | ||
1616 | |||
1617 | static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp, | ||
1618 | int *valp, | ||
1619 | int write, void *data) | ||
1620 | { | ||
1621 | int op = *(int *)data; | ||
1622 | if (write) { | ||
1623 | int val = *negp ? -*lvalp : *lvalp; | ||
1624 | switch(op) { | ||
1625 | case OP_SET: *valp = val; break; | ||
1626 | case OP_AND: *valp &= val; break; | ||
1627 | case OP_OR: *valp |= val; break; | ||
1628 | case OP_MAX: if(*valp < val) | ||
1629 | *valp = val; | ||
1630 | break; | ||
1631 | case OP_MIN: if(*valp > val) | ||
1632 | *valp = val; | ||
1633 | break; | ||
1634 | } | ||
1635 | } else { | ||
1636 | int val = *valp; | ||
1637 | if (val < 0) { | ||
1638 | *negp = -1; | ||
1639 | *lvalp = (unsigned long)-val; | ||
1640 | } else { | ||
1641 | *negp = 0; | ||
1642 | *lvalp = (unsigned long)val; | ||
1643 | } | ||
1644 | } | ||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | /* | ||
1649 | * init may raise the set. | ||
1650 | */ | ||
1651 | |||
1652 | int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, | ||
1653 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1654 | { | ||
1655 | int op; | ||
1656 | |||
1657 | if (!capable(CAP_SYS_MODULE)) { | ||
1658 | return -EPERM; | ||
1659 | } | ||
1660 | |||
1661 | op = (current->pid == 1) ? OP_SET : OP_AND; | ||
1662 | return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, | ||
1663 | do_proc_dointvec_bset_conv,&op); | ||
1664 | } | ||
1665 | |||
1666 | struct do_proc_dointvec_minmax_conv_param { | ||
1667 | int *min; | ||
1668 | int *max; | ||
1669 | }; | ||
1670 | |||
1671 | static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp, | ||
1672 | int *valp, | ||
1673 | int write, void *data) | ||
1674 | { | ||
1675 | struct do_proc_dointvec_minmax_conv_param *param = data; | ||
1676 | if (write) { | ||
1677 | int val = *negp ? -*lvalp : *lvalp; | ||
1678 | if ((param->min && *param->min > val) || | ||
1679 | (param->max && *param->max < val)) | ||
1680 | return -EINVAL; | ||
1681 | *valp = val; | ||
1682 | } else { | ||
1683 | int val = *valp; | ||
1684 | if (val < 0) { | ||
1685 | *negp = -1; | ||
1686 | *lvalp = (unsigned long)-val; | ||
1687 | } else { | ||
1688 | *negp = 0; | ||
1689 | *lvalp = (unsigned long)val; | ||
1690 | } | ||
1691 | } | ||
1692 | return 0; | ||
1693 | } | ||
1694 | |||
1695 | /** | ||
1696 | * proc_dointvec_minmax - read a vector of integers with min/max values | ||
1697 | * @table: the sysctl table | ||
1698 | * @write: %TRUE if this is a write to the sysctl file | ||
1699 | * @filp: the file structure | ||
1700 | * @buffer: the user buffer | ||
1701 | * @lenp: the size of the user buffer | ||
1702 | * @ppos: file position | ||
1703 | * | ||
1704 | * Reads/writes up to table->maxlen/sizeof(unsigned int) integer | ||
1705 | * values from/to the user buffer, treated as an ASCII string. | ||
1706 | * | ||
1707 | * This routine will ensure the values are within the range specified by | ||
1708 | * table->extra1 (min) and table->extra2 (max). | ||
1709 | * | ||
1710 | * Returns 0 on success. | ||
1711 | */ | ||
1712 | int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, | ||
1713 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1714 | { | ||
1715 | struct do_proc_dointvec_minmax_conv_param param = { | ||
1716 | .min = (int *) table->extra1, | ||
1717 | .max = (int *) table->extra2, | ||
1718 | }; | ||
1719 | return do_proc_dointvec(table, write, filp, buffer, lenp, ppos, | ||
1720 | do_proc_dointvec_minmax_conv, ¶m); | ||
1721 | } | ||
1722 | |||
1723 | static int do_proc_doulongvec_minmax(ctl_table *table, int write, | ||
1724 | struct file *filp, | ||
1725 | void __user *buffer, | ||
1726 | size_t *lenp, loff_t *ppos, | ||
1727 | unsigned long convmul, | ||
1728 | unsigned long convdiv) | ||
1729 | { | ||
1730 | #define TMPBUFLEN 21 | ||
1731 | unsigned long *i, *min, *max, val; | ||
1732 | int vleft, first=1, neg; | ||
1733 | size_t len, left; | ||
1734 | char buf[TMPBUFLEN], *p; | ||
1735 | char __user *s = buffer; | ||
1736 | |||
1737 | if (!table->data || !table->maxlen || !*lenp || | ||
1738 | (*ppos && !write)) { | ||
1739 | *lenp = 0; | ||
1740 | return 0; | ||
1741 | } | ||
1742 | |||
1743 | i = (unsigned long *) table->data; | ||
1744 | min = (unsigned long *) table->extra1; | ||
1745 | max = (unsigned long *) table->extra2; | ||
1746 | vleft = table->maxlen / sizeof(unsigned long); | ||
1747 | left = *lenp; | ||
1748 | |||
1749 | for (; left && vleft--; i++, min++, max++, first=0) { | ||
1750 | if (write) { | ||
1751 | while (left) { | ||
1752 | char c; | ||
1753 | if (get_user(c, s)) | ||
1754 | return -EFAULT; | ||
1755 | if (!isspace(c)) | ||
1756 | break; | ||
1757 | left--; | ||
1758 | s++; | ||
1759 | } | ||
1760 | if (!left) | ||
1761 | break; | ||
1762 | neg = 0; | ||
1763 | len = left; | ||
1764 | if (len > TMPBUFLEN-1) | ||
1765 | len = TMPBUFLEN-1; | ||
1766 | if (copy_from_user(buf, s, len)) | ||
1767 | return -EFAULT; | ||
1768 | buf[len] = 0; | ||
1769 | p = buf; | ||
1770 | if (*p == '-' && left > 1) { | ||
1771 | neg = 1; | ||
1772 | left--, p++; | ||
1773 | } | ||
1774 | if (*p < '0' || *p > '9') | ||
1775 | break; | ||
1776 | val = simple_strtoul(p, &p, 0) * convmul / convdiv ; | ||
1777 | len = p-buf; | ||
1778 | if ((len < left) && *p && !isspace(*p)) | ||
1779 | break; | ||
1780 | if (neg) | ||
1781 | val = -val; | ||
1782 | s += len; | ||
1783 | left -= len; | ||
1784 | |||
1785 | if(neg) | ||
1786 | continue; | ||
1787 | if ((min && val < *min) || (max && val > *max)) | ||
1788 | continue; | ||
1789 | *i = val; | ||
1790 | } else { | ||
1791 | p = buf; | ||
1792 | if (!first) | ||
1793 | *p++ = '\t'; | ||
1794 | sprintf(p, "%lu", convdiv * (*i) / convmul); | ||
1795 | len = strlen(buf); | ||
1796 | if (len > left) | ||
1797 | len = left; | ||
1798 | if(copy_to_user(s, buf, len)) | ||
1799 | return -EFAULT; | ||
1800 | left -= len; | ||
1801 | s += len; | ||
1802 | } | ||
1803 | } | ||
1804 | |||
1805 | if (!write && !first && left) { | ||
1806 | if(put_user('\n', s)) | ||
1807 | return -EFAULT; | ||
1808 | left--, s++; | ||
1809 | } | ||
1810 | if (write) { | ||
1811 | while (left) { | ||
1812 | char c; | ||
1813 | if (get_user(c, s++)) | ||
1814 | return -EFAULT; | ||
1815 | if (!isspace(c)) | ||
1816 | break; | ||
1817 | left--; | ||
1818 | } | ||
1819 | } | ||
1820 | if (write && first) | ||
1821 | return -EINVAL; | ||
1822 | *lenp -= left; | ||
1823 | *ppos += *lenp; | ||
1824 | return 0; | ||
1825 | #undef TMPBUFLEN | ||
1826 | } | ||
1827 | |||
1828 | /** | ||
1829 | * proc_doulongvec_minmax - read a vector of long integers with min/max values | ||
1830 | * @table: the sysctl table | ||
1831 | * @write: %TRUE if this is a write to the sysctl file | ||
1832 | * @filp: the file structure | ||
1833 | * @buffer: the user buffer | ||
1834 | * @lenp: the size of the user buffer | ||
1835 | * @ppos: file position | ||
1836 | * | ||
1837 | * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long | ||
1838 | * values from/to the user buffer, treated as an ASCII string. | ||
1839 | * | ||
1840 | * This routine will ensure the values are within the range specified by | ||
1841 | * table->extra1 (min) and table->extra2 (max). | ||
1842 | * | ||
1843 | * Returns 0 on success. | ||
1844 | */ | ||
1845 | int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, | ||
1846 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1847 | { | ||
1848 | return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, ppos, 1l, 1l); | ||
1849 | } | ||
1850 | |||
1851 | /** | ||
1852 | * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values | ||
1853 | * @table: the sysctl table | ||
1854 | * @write: %TRUE if this is a write to the sysctl file | ||
1855 | * @filp: the file structure | ||
1856 | * @buffer: the user buffer | ||
1857 | * @lenp: the size of the user buffer | ||
1858 | * @ppos: file position | ||
1859 | * | ||
1860 | * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long | ||
1861 | * values from/to the user buffer, treated as an ASCII string. The values | ||
1862 | * are treated as milliseconds, and converted to jiffies when they are stored. | ||
1863 | * | ||
1864 | * This routine will ensure the values are within the range specified by | ||
1865 | * table->extra1 (min) and table->extra2 (max). | ||
1866 | * | ||
1867 | * Returns 0 on success. | ||
1868 | */ | ||
1869 | int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, | ||
1870 | struct file *filp, | ||
1871 | void __user *buffer, | ||
1872 | size_t *lenp, loff_t *ppos) | ||
1873 | { | ||
1874 | return do_proc_doulongvec_minmax(table, write, filp, buffer, | ||
1875 | lenp, ppos, HZ, 1000l); | ||
1876 | } | ||
1877 | |||
1878 | |||
1879 | static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp, | ||
1880 | int *valp, | ||
1881 | int write, void *data) | ||
1882 | { | ||
1883 | if (write) { | ||
1884 | *valp = *negp ? -(*lvalp*HZ) : (*lvalp*HZ); | ||
1885 | } else { | ||
1886 | int val = *valp; | ||
1887 | unsigned long lval; | ||
1888 | if (val < 0) { | ||
1889 | *negp = -1; | ||
1890 | lval = (unsigned long)-val; | ||
1891 | } else { | ||
1892 | *negp = 0; | ||
1893 | lval = (unsigned long)val; | ||
1894 | } | ||
1895 | *lvalp = lval / HZ; | ||
1896 | } | ||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp, | ||
1901 | int *valp, | ||
1902 | int write, void *data) | ||
1903 | { | ||
1904 | if (write) { | ||
1905 | *valp = clock_t_to_jiffies(*negp ? -*lvalp : *lvalp); | ||
1906 | } else { | ||
1907 | int val = *valp; | ||
1908 | unsigned long lval; | ||
1909 | if (val < 0) { | ||
1910 | *negp = -1; | ||
1911 | lval = (unsigned long)-val; | ||
1912 | } else { | ||
1913 | *negp = 0; | ||
1914 | lval = (unsigned long)val; | ||
1915 | } | ||
1916 | *lvalp = jiffies_to_clock_t(lval); | ||
1917 | } | ||
1918 | return 0; | ||
1919 | } | ||
1920 | |||
1921 | static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp, | ||
1922 | int *valp, | ||
1923 | int write, void *data) | ||
1924 | { | ||
1925 | if (write) { | ||
1926 | *valp = msecs_to_jiffies(*negp ? -*lvalp : *lvalp); | ||
1927 | } else { | ||
1928 | int val = *valp; | ||
1929 | unsigned long lval; | ||
1930 | if (val < 0) { | ||
1931 | *negp = -1; | ||
1932 | lval = (unsigned long)-val; | ||
1933 | } else { | ||
1934 | *negp = 0; | ||
1935 | lval = (unsigned long)val; | ||
1936 | } | ||
1937 | *lvalp = jiffies_to_msecs(lval); | ||
1938 | } | ||
1939 | return 0; | ||
1940 | } | ||
1941 | |||
1942 | /** | ||
1943 | * proc_dointvec_jiffies - read a vector of integers as seconds | ||
1944 | * @table: the sysctl table | ||
1945 | * @write: %TRUE if this is a write to the sysctl file | ||
1946 | * @filp: the file structure | ||
1947 | * @buffer: the user buffer | ||
1948 | * @lenp: the size of the user buffer | ||
1949 | * @ppos: file position | ||
1950 | * | ||
1951 | * Reads/writes up to table->maxlen/sizeof(unsigned int) integer | ||
1952 | * values from/to the user buffer, treated as an ASCII string. | ||
1953 | * The values read are assumed to be in seconds, and are converted into | ||
1954 | * jiffies. | ||
1955 | * | ||
1956 | * Returns 0 on success. | ||
1957 | */ | ||
1958 | int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, | ||
1959 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1960 | { | ||
1961 | return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, | ||
1962 | do_proc_dointvec_jiffies_conv,NULL); | ||
1963 | } | ||
1964 | |||
1965 | /** | ||
1966 | * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds | ||
1967 | * @table: the sysctl table | ||
1968 | * @write: %TRUE if this is a write to the sysctl file | ||
1969 | * @filp: the file structure | ||
1970 | * @buffer: the user buffer | ||
1971 | * @lenp: the size of the user buffer | ||
1972 | * | ||
1973 | * Reads/writes up to table->maxlen/sizeof(unsigned int) integer | ||
1974 | * values from/to the user buffer, treated as an ASCII string. | ||
1975 | * The values read are assumed to be in 1/USER_HZ seconds, and | ||
1976 | * are converted into jiffies. | ||
1977 | * | ||
1978 | * Returns 0 on success. | ||
1979 | */ | ||
1980 | int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, | ||
1981 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1982 | { | ||
1983 | return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, | ||
1984 | do_proc_dointvec_userhz_jiffies_conv,NULL); | ||
1985 | } | ||
1986 | |||
1987 | /** | ||
1988 | * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds | ||
1989 | * @table: the sysctl table | ||
1990 | * @write: %TRUE if this is a write to the sysctl file | ||
1991 | * @filp: the file structure | ||
1992 | * @buffer: the user buffer | ||
1993 | * @lenp: the size of the user buffer | ||
1994 | * | ||
1995 | * Reads/writes up to table->maxlen/sizeof(unsigned int) integer | ||
1996 | * values from/to the user buffer, treated as an ASCII string. | ||
1997 | * The values read are assumed to be in 1/1000 seconds, and | ||
1998 | * are converted into jiffies. | ||
1999 | * | ||
2000 | * Returns 0 on success. | ||
2001 | */ | ||
2002 | int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, | ||
2003 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2004 | { | ||
2005 | return do_proc_dointvec(table, write, filp, buffer, lenp, ppos, | ||
2006 | do_proc_dointvec_ms_jiffies_conv, NULL); | ||
2007 | } | ||
2008 | |||
2009 | #else /* CONFIG_PROC_FS */ | ||
2010 | |||
2011 | int proc_dostring(ctl_table *table, int write, struct file *filp, | ||
2012 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2013 | { | ||
2014 | return -ENOSYS; | ||
2015 | } | ||
2016 | |||
2017 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | ||
2018 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2019 | { | ||
2020 | return -ENOSYS; | ||
2021 | } | ||
2022 | |||
2023 | int proc_dointvec(ctl_table *table, int write, struct file *filp, | ||
2024 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2025 | { | ||
2026 | return -ENOSYS; | ||
2027 | } | ||
2028 | |||
2029 | int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, | ||
2030 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2031 | { | ||
2032 | return -ENOSYS; | ||
2033 | } | ||
2034 | |||
2035 | int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, | ||
2036 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2037 | { | ||
2038 | return -ENOSYS; | ||
2039 | } | ||
2040 | |||
2041 | int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, | ||
2042 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2043 | { | ||
2044 | return -ENOSYS; | ||
2045 | } | ||
2046 | |||
2047 | int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, | ||
2048 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2049 | { | ||
2050 | return -ENOSYS; | ||
2051 | } | ||
2052 | |||
2053 | int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, | ||
2054 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2055 | { | ||
2056 | return -ENOSYS; | ||
2057 | } | ||
2058 | |||
2059 | int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, | ||
2060 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2061 | { | ||
2062 | return -ENOSYS; | ||
2063 | } | ||
2064 | |||
2065 | int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, | ||
2066 | struct file *filp, | ||
2067 | void __user *buffer, | ||
2068 | size_t *lenp, loff_t *ppos) | ||
2069 | { | ||
2070 | return -ENOSYS; | ||
2071 | } | ||
2072 | |||
2073 | |||
2074 | #endif /* CONFIG_PROC_FS */ | ||
2075 | |||
2076 | |||
2077 | /* | ||
2078 | * General sysctl support routines | ||
2079 | */ | ||
2080 | |||
2081 | /* The generic string strategy routine: */ | ||
2082 | int sysctl_string(ctl_table *table, int __user *name, int nlen, | ||
2083 | void __user *oldval, size_t __user *oldlenp, | ||
2084 | void __user *newval, size_t newlen, void **context) | ||
2085 | { | ||
2086 | size_t l, len; | ||
2087 | |||
2088 | if (!table->data || !table->maxlen) | ||
2089 | return -ENOTDIR; | ||
2090 | |||
2091 | if (oldval && oldlenp) { | ||
2092 | if (get_user(len, oldlenp)) | ||
2093 | return -EFAULT; | ||
2094 | if (len) { | ||
2095 | l = strlen(table->data); | ||
2096 | if (len > l) len = l; | ||
2097 | if (len >= table->maxlen) | ||
2098 | len = table->maxlen; | ||
2099 | if(copy_to_user(oldval, table->data, len)) | ||
2100 | return -EFAULT; | ||
2101 | if(put_user(0, ((char __user *) oldval) + len)) | ||
2102 | return -EFAULT; | ||
2103 | if(put_user(len, oldlenp)) | ||
2104 | return -EFAULT; | ||
2105 | } | ||
2106 | } | ||
2107 | if (newval && newlen) { | ||
2108 | len = newlen; | ||
2109 | if (len > table->maxlen) | ||
2110 | len = table->maxlen; | ||
2111 | if(copy_from_user(table->data, newval, len)) | ||
2112 | return -EFAULT; | ||
2113 | if (len == table->maxlen) | ||
2114 | len--; | ||
2115 | ((char *) table->data)[len] = 0; | ||
2116 | } | ||
2117 | return 0; | ||
2118 | } | ||
2119 | |||
2120 | /* | ||
2121 | * This function makes sure that all of the integers in the vector | ||
2122 | * are between the minimum and maximum values given in the arrays | ||
2123 | * table->extra1 and table->extra2, respectively. | ||
2124 | */ | ||
2125 | int sysctl_intvec(ctl_table *table, int __user *name, int nlen, | ||
2126 | void __user *oldval, size_t __user *oldlenp, | ||
2127 | void __user *newval, size_t newlen, void **context) | ||
2128 | { | ||
2129 | |||
2130 | if (newval && newlen) { | ||
2131 | int __user *vec = (int __user *) newval; | ||
2132 | int *min = (int *) table->extra1; | ||
2133 | int *max = (int *) table->extra2; | ||
2134 | size_t length; | ||
2135 | int i; | ||
2136 | |||
2137 | if (newlen % sizeof(int) != 0) | ||
2138 | return -EINVAL; | ||
2139 | |||
2140 | if (!table->extra1 && !table->extra2) | ||
2141 | return 0; | ||
2142 | |||
2143 | if (newlen > table->maxlen) | ||
2144 | newlen = table->maxlen; | ||
2145 | length = newlen / sizeof(int); | ||
2146 | |||
2147 | for (i = 0; i < length; i++) { | ||
2148 | int value; | ||
2149 | if (get_user(value, vec + i)) | ||
2150 | return -EFAULT; | ||
2151 | if (min && value < min[i]) | ||
2152 | return -EINVAL; | ||
2153 | if (max && value > max[i]) | ||
2154 | return -EINVAL; | ||
2155 | } | ||
2156 | } | ||
2157 | return 0; | ||
2158 | } | ||
2159 | |||
2160 | /* Strategy function to convert jiffies to seconds */ | ||
2161 | int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, | ||
2162 | void __user *oldval, size_t __user *oldlenp, | ||
2163 | void __user *newval, size_t newlen, void **context) | ||
2164 | { | ||
2165 | if (oldval) { | ||
2166 | size_t olen; | ||
2167 | if (oldlenp) { | ||
2168 | if (get_user(olen, oldlenp)) | ||
2169 | return -EFAULT; | ||
2170 | if (olen!=sizeof(int)) | ||
2171 | return -EINVAL; | ||
2172 | } | ||
2173 | if (put_user(*(int *)(table->data)/HZ, (int __user *)oldval) || | ||
2174 | (oldlenp && put_user(sizeof(int),oldlenp))) | ||
2175 | return -EFAULT; | ||
2176 | } | ||
2177 | if (newval && newlen) { | ||
2178 | int new; | ||
2179 | if (newlen != sizeof(int)) | ||
2180 | return -EINVAL; | ||
2181 | if (get_user(new, (int __user *)newval)) | ||
2182 | return -EFAULT; | ||
2183 | *(int *)(table->data) = new*HZ; | ||
2184 | } | ||
2185 | return 1; | ||
2186 | } | ||
2187 | |||
2188 | /* Strategy function to convert jiffies to seconds */ | ||
2189 | int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, | ||
2190 | void __user *oldval, size_t __user *oldlenp, | ||
2191 | void __user *newval, size_t newlen, void **context) | ||
2192 | { | ||
2193 | if (oldval) { | ||
2194 | size_t olen; | ||
2195 | if (oldlenp) { | ||
2196 | if (get_user(olen, oldlenp)) | ||
2197 | return -EFAULT; | ||
2198 | if (olen!=sizeof(int)) | ||
2199 | return -EINVAL; | ||
2200 | } | ||
2201 | if (put_user(jiffies_to_msecs(*(int *)(table->data)), (int __user *)oldval) || | ||
2202 | (oldlenp && put_user(sizeof(int),oldlenp))) | ||
2203 | return -EFAULT; | ||
2204 | } | ||
2205 | if (newval && newlen) { | ||
2206 | int new; | ||
2207 | if (newlen != sizeof(int)) | ||
2208 | return -EINVAL; | ||
2209 | if (get_user(new, (int __user *)newval)) | ||
2210 | return -EFAULT; | ||
2211 | *(int *)(table->data) = msecs_to_jiffies(new); | ||
2212 | } | ||
2213 | return 1; | ||
2214 | } | ||
2215 | |||
2216 | #else /* CONFIG_SYSCTL */ | ||
2217 | |||
2218 | |||
2219 | asmlinkage long sys_sysctl(struct __sysctl_args __user *args) | ||
2220 | { | ||
2221 | return -ENOSYS; | ||
2222 | } | ||
2223 | |||
2224 | int sysctl_string(ctl_table *table, int __user *name, int nlen, | ||
2225 | void __user *oldval, size_t __user *oldlenp, | ||
2226 | void __user *newval, size_t newlen, void **context) | ||
2227 | { | ||
2228 | return -ENOSYS; | ||
2229 | } | ||
2230 | |||
2231 | int sysctl_intvec(ctl_table *table, int __user *name, int nlen, | ||
2232 | void __user *oldval, size_t __user *oldlenp, | ||
2233 | void __user *newval, size_t newlen, void **context) | ||
2234 | { | ||
2235 | return -ENOSYS; | ||
2236 | } | ||
2237 | |||
2238 | int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, | ||
2239 | void __user *oldval, size_t __user *oldlenp, | ||
2240 | void __user *newval, size_t newlen, void **context) | ||
2241 | { | ||
2242 | return -ENOSYS; | ||
2243 | } | ||
2244 | |||
2245 | int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, | ||
2246 | void __user *oldval, size_t __user *oldlenp, | ||
2247 | void __user *newval, size_t newlen, void **context) | ||
2248 | { | ||
2249 | return -ENOSYS; | ||
2250 | } | ||
2251 | |||
2252 | int proc_dostring(ctl_table *table, int write, struct file *filp, | ||
2253 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2254 | { | ||
2255 | return -ENOSYS; | ||
2256 | } | ||
2257 | |||
2258 | int proc_dointvec(ctl_table *table, int write, struct file *filp, | ||
2259 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2260 | { | ||
2261 | return -ENOSYS; | ||
2262 | } | ||
2263 | |||
2264 | int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, | ||
2265 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2266 | { | ||
2267 | return -ENOSYS; | ||
2268 | } | ||
2269 | |||
2270 | int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, | ||
2271 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2272 | { | ||
2273 | return -ENOSYS; | ||
2274 | } | ||
2275 | |||
2276 | int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, | ||
2277 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2278 | { | ||
2279 | return -ENOSYS; | ||
2280 | } | ||
2281 | |||
2282 | int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, | ||
2283 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2284 | { | ||
2285 | return -ENOSYS; | ||
2286 | } | ||
2287 | |||
2288 | int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, | ||
2289 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2290 | { | ||
2291 | return -ENOSYS; | ||
2292 | } | ||
2293 | |||
2294 | int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, | ||
2295 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2296 | { | ||
2297 | return -ENOSYS; | ||
2298 | } | ||
2299 | |||
2300 | int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, | ||
2301 | struct file *filp, | ||
2302 | void __user *buffer, | ||
2303 | size_t *lenp, loff_t *ppos) | ||
2304 | { | ||
2305 | return -ENOSYS; | ||
2306 | } | ||
2307 | |||
2308 | struct ctl_table_header * register_sysctl_table(ctl_table * table, | ||
2309 | int insert_at_head) | ||
2310 | { | ||
2311 | return NULL; | ||
2312 | } | ||
2313 | |||
2314 | void unregister_sysctl_table(struct ctl_table_header * table) | ||
2315 | { | ||
2316 | } | ||
2317 | |||
2318 | #endif /* CONFIG_SYSCTL */ | ||
2319 | |||
2320 | /* | ||
2321 | * No sense putting this after each symbol definition, twice, | ||
2322 | * exception granted :-) | ||
2323 | */ | ||
2324 | EXPORT_SYMBOL(proc_dointvec); | ||
2325 | EXPORT_SYMBOL(proc_dointvec_jiffies); | ||
2326 | EXPORT_SYMBOL(proc_dointvec_minmax); | ||
2327 | EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); | ||
2328 | EXPORT_SYMBOL(proc_dointvec_ms_jiffies); | ||
2329 | EXPORT_SYMBOL(proc_dostring); | ||
2330 | EXPORT_SYMBOL(proc_doulongvec_minmax); | ||
2331 | EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); | ||
2332 | EXPORT_SYMBOL(register_sysctl_table); | ||
2333 | EXPORT_SYMBOL(sysctl_intvec); | ||
2334 | EXPORT_SYMBOL(sysctl_jiffies); | ||
2335 | EXPORT_SYMBOL(sysctl_ms_jiffies); | ||
2336 | EXPORT_SYMBOL(sysctl_string); | ||
2337 | EXPORT_SYMBOL(unregister_sysctl_table); | ||