~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/kernel/sysctl.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/malloc.h>
 23 #include <linux/sysctl.h>
 24 #include <linux/swapctl.h>
 25 #include <linux/proc_fs.h>
 26 #include <linux/ctype.h>
 27 #include <linux/utsname.h>
 28 #include <linux/capability.h>
 29 #include <linux/smp_lock.h>
 30 #include <linux/init.h>
 31 #include <linux/sysrq.h>
 32 #include <linux/highuid.h>
 33 
 34 #include <asm/uaccess.h>
 35 
 36 #ifdef CONFIG_ROOT_NFS
 37 #include <linux/nfs_fs.h>
 38 #endif
 39 
 40 #if defined(CONFIG_SYSCTL)
 41 
 42 /* External variables not in a header file. */
 43 extern int panic_timeout;
 44 extern int C_A_D;
 45 extern int bdf_prm[], bdflush_min[], bdflush_max[];
 46 extern int sysctl_overcommit_memory;
 47 extern int max_threads;
 48 extern int nr_queued_signals, max_queued_signals;
 49 extern int sysrq_enabled;
 50 
 51 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 52 static int maxolduid = 65535;
 53 static int minolduid;
 54 
 55 #ifdef CONFIG_KMOD
 56 extern char modprobe_path[];
 57 #endif
 58 #ifdef CONFIG_HOTPLUG
 59 extern char hotplug_path[];
 60 #endif
 61 #ifdef CONFIG_CHR_DEV_SG
 62 extern int sg_big_buff;
 63 #endif
 64 #ifdef CONFIG_SYSVIPC
 65 extern size_t shm_ctlmax;
 66 extern size_t shm_ctlall;
 67 extern int shm_ctlmni;
 68 extern int msg_ctlmax;
 69 extern int msg_ctlmnb;
 70 extern int msg_ctlmni;
 71 extern int sem_ctls[];
 72 #endif
 73 
 74 #ifdef __sparc__
 75 extern char reboot_command [];
 76 extern int stop_a_enabled;
 77 #endif
 78 #ifdef __powerpc__
 79 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
 80 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
 81                   void *buffer, size_t *lenp);
 82 #endif
 83 
 84 #ifdef CONFIG_BSD_PROCESS_ACCT
 85 extern int acct_parm[];
 86 #endif
 87 
 88 extern int pgt_cache_water[];
 89 
 90 static int parse_table(int *, int, void *, size_t *, void *, size_t,
 91                        ctl_table *, void **);
 92 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
 93                   void *buffer, size_t *lenp);
 94 
 95 static ctl_table root_table[];
 96 static struct ctl_table_header root_table_header =
 97         { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
 98 
 99 static ctl_table kern_table[];
100 static ctl_table vm_table[];
101 #ifdef CONFIG_NET
102 extern ctl_table net_table[];
103 #endif
104 static ctl_table proc_table[];
105 static ctl_table fs_table[];
106 static ctl_table debug_table[];
107 static ctl_table dev_table[];
108 extern ctl_table random_table[];
109 
110 /* /proc declarations: */
111 
112 #ifdef CONFIG_PROC_FS
113 
114 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
115 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
116 static int proc_sys_permission(struct inode *, int);
117 
118 struct file_operations proc_sys_file_operations = {
119         read:           proc_readsys,
120         write:          proc_writesys,
121 };
122 
123 static struct inode_operations proc_sys_inode_operations = {
124         permission:     proc_sys_permission,
125 };
126 
127 extern struct proc_dir_entry *proc_sys_root;
128 
129 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
130 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
131 #endif
132 
133 extern int inodes_stat[];
134 extern int dentry_stat[];
135 
136 /* The default sysctl tables: */
137 
138 static ctl_table root_table[] = {
139         {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
140         {CTL_VM, "vm", NULL, 0, 0555, vm_table},
141 #ifdef CONFIG_NET
142         {CTL_NET, "net", NULL, 0, 0555, net_table},
143 #endif
144         {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
145         {CTL_FS, "fs", NULL, 0, 0555, fs_table},
146         {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
147         {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
148         {0}
149 };
150 
151 static ctl_table kern_table[] = {
152         {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
153          0444, NULL, &proc_doutsstring, &sysctl_string},
154         {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
155          0444, NULL, &proc_doutsstring, &sysctl_string},
156         {KERN_VERSION, "version", system_utsname.version, 64,
157          0444, NULL, &proc_doutsstring, &sysctl_string},
158         {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
159          0644, NULL, &proc_doutsstring, &sysctl_string},
160         {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
161          0644, NULL, &proc_doutsstring, &sysctl_string},
162         {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
163          0644, NULL, &proc_dointvec},
164         {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
165          0600, NULL, &proc_dointvec_bset},
166 #ifdef CONFIG_BLK_DEV_INITRD
167         {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
168          0644, NULL, &proc_dointvec},
169 #endif
170 #ifdef __sparc__
171         {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
172          256, 0644, NULL, &proc_dostring, &sysctl_string },
173         {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
174          0644, NULL, &proc_dointvec},
175 #endif
176 #ifdef __powerpc__
177         {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
178          0644, NULL, &proc_dointvec},
179         {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
180          0644, NULL, &proc_dointvec},
181         {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
182          0644, NULL, &proc_dointvec},
183         {KERN_PPC_L2CR, "l2cr", NULL, 0,
184          0644, NULL, &proc_dol2crvec},
185 #endif
186         {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
187          0644, NULL, &proc_dointvec},
188         {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
189          0644, NULL, &proc_dointvec},
190 #ifdef CONFIG_KMOD
191         {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
192          0644, NULL, &proc_dostring, &sysctl_string },
193 #endif
194 #ifdef CONFIG_HOTPLUG
195         {KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
196          0644, NULL, &proc_dostring, &sysctl_string },
197 #endif
198 #ifdef CONFIG_CHR_DEV_SG
199         {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
200          0444, NULL, &proc_dointvec},
201 #endif
202 #ifdef CONFIG_BSD_PROCESS_ACCT
203         {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
204         0644, NULL, &proc_dointvec},
205 #endif
206         {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
207          0444, NULL, &proc_dointvec},
208         {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
209          0644, NULL, &proc_dointvec},
210 #ifdef CONFIG_SYSVIPC
211         {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
212          0644, NULL, &proc_doulongvec_minmax},
213         {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (size_t),
214          0644, NULL, &proc_doulongvec_minmax},
215         {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
216          0644, NULL, &proc_dointvec},
217         {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
218          0644, NULL, &proc_dointvec},
219         {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
220          0644, NULL, &proc_dointvec},
221         {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
222          0644, NULL, &proc_dointvec},
223         {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
224          0644, NULL, &proc_dointvec},
225 #endif
226 #ifdef CONFIG_MAGIC_SYSRQ
227         {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
228          0644, NULL, &proc_dointvec},
229 #endif   
230         {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
231          0644, NULL, &proc_dointvec},
232         {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
233         {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
234          &proc_dointvec_minmax, &sysctl_intvec, NULL,
235          &minolduid, &maxolduid},
236         {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
237          &proc_dointvec_minmax, &sysctl_intvec, NULL,
238          &minolduid, &maxolduid},
239         {0}
240 };
241 
242 static ctl_table vm_table[] = {
243         {VM_FREEPG, "freepages", 
244          &freepages, sizeof(freepages_t), 0444, NULL, &proc_dointvec},
245         {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
246          &proc_dointvec_minmax, &sysctl_intvec, NULL,
247          &bdflush_min, &bdflush_max},
248         {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
249          sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
250         {VM_BUFFERMEM, "buffermem",
251          &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
252         {VM_PAGECACHE, "pagecache",
253          &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
254         {VM_PAGERDAEMON, "kswapd",
255          &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
256         {VM_PGT_CACHE, "pagetable_cache", 
257          &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
258         {VM_PAGE_CLUSTER, "page-cluster", 
259          &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
260         {0}
261 };
262 
263 static ctl_table proc_table[] = {
264         {0}
265 };
266 
267 static ctl_table fs_table[] = {
268         {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
269          0444, NULL, &proc_dointvec},
270         {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
271          0444, NULL, &proc_dointvec},
272         {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
273          0444, NULL, &proc_dointvec},
274         {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
275          0644, NULL, &proc_dointvec},
276         {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
277          0444, NULL, &proc_dointvec},
278         {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
279          0644, NULL, &proc_dointvec},
280         {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
281          0444, NULL, &proc_dointvec},
282         {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
283          0644, NULL, &proc_dointvec},
284         {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
285          0444, NULL, &proc_dointvec},
286         {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
287          &proc_dointvec_minmax, &sysctl_intvec, NULL,
288          &minolduid, &maxolduid},
289         {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
290          &proc_dointvec_minmax, &sysctl_intvec, NULL,
291          &minolduid, &maxolduid},
292         {FS_LEASES, "leases-enable", &leases_enable, sizeof(int),
293          0644, NULL, &proc_dointvec},
294         {FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable,
295          sizeof(int), 0644, NULL, &proc_dointvec},
296         {FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int),
297          0644, NULL, &proc_dointvec},
298         {0}
299 };
300 
301 static ctl_table debug_table[] = {
302         {0}
303 };
304 
305 static ctl_table dev_table[] = {
306         {0}
307 };  
308 
309 extern void init_irq_proc (void);
310 
311 void __init sysctl_init(void)
312 {
313 #ifdef CONFIG_PROC_FS
314         register_proc_table(root_table, proc_sys_root);
315         init_irq_proc();
316 #endif
317 }
318 
319 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
320                void *newval, size_t newlen)
321 {
322         struct list_head *tmp;
323 
324         if (nlen == 0 || nlen >= CTL_MAXNAME)
325                 return -ENOTDIR;
326         if (oldval) {
327                 int old_len;
328                 if (!oldlenp || get_user(old_len, oldlenp))
329                         return -EFAULT;
330         }
331         tmp = &root_table_header.ctl_entry;
332         do {
333                 struct ctl_table_header *head =
334                         list_entry(tmp, struct ctl_table_header, ctl_entry);
335                 void *context = NULL;
336                 int error = parse_table(name, nlen, oldval, oldlenp, 
337                                         newval, newlen, head->ctl_table,
338                                         &context);
339                 if (context)
340                         kfree(context);
341                 if (error != -ENOTDIR)
342                         return error;
343                 tmp = tmp->next;
344         } while (tmp != &root_table_header.ctl_entry);
345         return -ENOTDIR;
346 }
347 
348 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
349 {
350         struct __sysctl_args tmp;
351         int error;
352 
353         if (copy_from_user(&tmp, args, sizeof(tmp)))
354                 return -EFAULT;
355                 
356         lock_kernel();
357         error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
358                           tmp.newval, tmp.newlen);
359         unlock_kernel();
360         return error;
361 }
362 
363 /*
364  * ctl_perm does NOT grant the superuser all rights automatically, because
365  * some sysctl variables are readonly even to root.
366  */
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 n;
390 repeat:
391         if (!nlen)
392                 return -ENOTDIR;
393         if (get_user(n, name))
394                 return -EFAULT;
395         for ( ; table->ctl_name; table++) {
396                 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
397                         int error;
398                         if (table->child) {
399                                 if (ctl_perm(table, 001))
400                                         return -EPERM;
401                                 if (table->strategy) {
402                                         error = table->strategy(
403                                                 table, name, nlen,
404                                                 oldval, oldlenp,
405                                                 newval, newlen, context);
406                                         if (error)
407                                                 return error;
408                                 }
409                                 name++;
410                                 nlen--;
411                                 table = table->child;
412                                 goto repeat;
413                         }
414                         error = do_sysctl_strategy(table, name, nlen,
415                                                    oldval, oldlenp,
416                                                    newval, newlen, context);
417                         return error;
418                 }
419         }
420         return -ENOTDIR;
421 }
422 
423 /* Perform the actual read/write of a sysctl table entry. */
424 int do_sysctl_strategy (ctl_table *table, 
425                         int *name, int nlen,
426                         void *oldval, size_t *oldlenp,
427                         void *newval, size_t newlen, void **context)
428 {
429         int op = 0, rc, len;
430 
431         if (oldval)
432                 op |= 004;
433         if (newval) 
434                 op |= 002;
435         if (ctl_perm(table, op))
436                 return -EPERM;
437 
438         if (table->strategy) {
439                 rc = table->strategy(table, name, nlen, oldval, oldlenp,
440                                      newval, newlen, context);
441                 if (rc < 0)
442                         return rc;
443                 if (rc > 0)
444                         return 0;
445         }
446 
447         /* If there is no strategy routine, or if the strategy returns
448          * zero, proceed with automatic r/w */
449         if (table->data && table->maxlen) {
450                 if (oldval && oldlenp) {
451                         get_user(len, oldlenp);
452                         if (len) {
453                                 if (len > table->maxlen)
454                                         len = table->maxlen;
455                                 if(copy_to_user(oldval, table->data, len))
456                                         return -EFAULT;
457                                 if(put_user(len, oldlenp))
458                                         return -EFAULT;
459                         }
460                 }
461                 if (newval && newlen) {
462                         len = newlen;
463                         if (len > table->maxlen)
464                                 len = table->maxlen;
465                         if(copy_from_user(table->data, newval, len))
466                                 return -EFAULT;
467                 }
468         }
469         return 0;
470 }
471 
472 struct ctl_table_header *register_sysctl_table(ctl_table * table, 
473                                                int insert_at_head)
474 {
475         struct ctl_table_header *tmp;
476         tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
477         if (!tmp)
478                 return 0;
479         tmp->ctl_table = table;
480         INIT_LIST_HEAD(&tmp->ctl_entry);
481         if (insert_at_head)
482                 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
483         else
484                 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
485 #ifdef CONFIG_PROC_FS
486         register_proc_table(table, proc_sys_root);
487 #endif
488         return tmp;
489 }
490 
491 /*
492  * Unlink and free a ctl_table.
493  */
494 void unregister_sysctl_table(struct ctl_table_header * header)
495 {
496         list_del(&header->ctl_entry);
497 #ifdef CONFIG_PROC_FS
498         unregister_proc_table(header->ctl_table, proc_sys_root);
499 #endif
500         kfree(header);
501 }
502 
503 /*
504  * /proc/sys support
505  */
506 
507 #ifdef CONFIG_PROC_FS
508 
509 /* Scan the sysctl entries in table and add them all into /proc */
510 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
511 {
512         struct proc_dir_entry *de;
513         int len;
514         mode_t mode;
515         
516         for (; table->ctl_name; table++) {
517                 /* Can't do anything without a proc name. */
518                 if (!table->procname)
519                         continue;
520                 /* Maybe we can't do anything with it... */
521                 if (!table->proc_handler && !table->child) {
522                         printk(KERN_WARNING "SYSCTL: Can't register %s\n",
523                                 table->procname);
524                         continue;
525                 }
526 
527                 len = strlen(table->procname);
528                 mode = table->mode;
529 
530                 de = NULL;
531                 if (table->proc_handler)
532                         mode |= S_IFREG;
533                 else {
534                         mode |= S_IFDIR;
535                         for (de = root->subdir; de; de = de->next) {
536                                 if (proc_match(len, table->procname, de))
537                                         break;
538                         }
539                         /* If the subdir exists already, de is non-NULL */
540                 }
541 
542                 if (!de) {
543                         de = create_proc_entry(table->procname, mode, root);
544                         if (!de)
545                                 continue;
546                         de->data = (void *) table;
547                         if (table->proc_handler) {
548                                 de->proc_fops = &proc_sys_file_operations;
549                                 de->proc_iops = &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 (atomic_read(&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 
712 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
713                   void *buffer, size_t *lenp, int conv, int op)
714 {
715         int *i, vleft, first=1, len, left, neg, val;
716         #define TMPBUFLEN 20
717         char buf[TMPBUFLEN], *p;
718         
719         if (!table->data || !table->maxlen || !*lenp ||
720             (filp->f_pos && !write)) {
721                 *lenp = 0;
722                 return 0;
723         }
724         
725         i = (int *) table->data;
726         vleft = table->maxlen / sizeof(int);
727         left = *lenp;
728         
729         for (; left && vleft--; i++, first=0) {
730                 if (write) {
731                         while (left) {
732                                 char c;
733                                 if(get_user(c,(char *) buffer))
734                                         return -EFAULT;
735                                 if (!isspace(c))
736                                         break;
737                                 left--;
738                                 ((char *) buffer)++;
739                         }
740                         if (!left)
741                                 break;
742                         neg = 0;
743                         len = left;
744                         if (len > TMPBUFLEN-1)
745                                 len = TMPBUFLEN-1;
746                         if(copy_from_user(buf, buffer, len))
747                                 return -EFAULT;
748                         buf[len] = 0;
749                         p = buf;
750                         if (*p == '-' && left > 1) {
751                                 neg = 1;
752                                 left--, p++;
753                         }
754                         if (*p < '' || *p > '9')
755                                 break;
756                         val = simple_strtoul(p, &p, 0) * conv;
757                         len = p-buf;
758                         if ((len < left) && *p && !isspace(*p))
759                                 break;
760                         if (neg)
761                                 val = -val;
762                         buffer += len;
763                         left -= len;
764                         switch(op) {
765                         case OP_SET:    *i = val; break;
766                         case OP_AND:    *i &= val; break;
767                         case OP_OR:     *i |= val; break;
768                         case OP_MAX:    if(*i < val)
769                                                 *i = val;
770                                         break;
771                         case OP_MIN:    if(*i > val)
772                                                 *i = val;
773                                         break;
774                         }
775                 } else {
776                         p = buf;
777                         if (!first)
778                                 *p++ = '\t';
779                         sprintf(p, "%d", (*i) / conv);
780                         len = strlen(buf);
781                         if (len > left)
782                                 len = left;
783                         if(copy_to_user(buffer, buf, len))
784                                 return -EFAULT;
785                         left -= len;
786                         buffer += len;
787                 }
788         }
789 
790         if (!write && !first && left) {
791                 if(put_user('\n', (char *) buffer))
792                         return -EFAULT;
793                 left--, buffer++;
794         }
795         if (write) {
796                 p = (char *) buffer;
797                 while (left) {
798                         char c;
799                         if(get_user(c, p++))
800                                 return -EFAULT;
801                         if (!isspace(c))
802                                 break;
803                         left--;
804                 }
805         }
806         if (write && first)
807                 return -EINVAL;
808         *lenp -= left;
809         filp->f_pos += *lenp;
810         return 0;
811 }
812 
813 int proc_dointvec(ctl_table *table, int write, struct file *filp,
814                      void *buffer, size_t *lenp)
815 {
816     return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
817 }
818 
819 /*
820  *      init may raise the set.
821  */
822  
823 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
824                         void *buffer, size_t *lenp)
825 {
826         if (!capable(CAP_SYS_MODULE)) {
827                 return -EPERM;
828         }
829         return do_proc_dointvec(table,write,filp,buffer,lenp,1,
830                                 (current->pid == 1) ? OP_SET : OP_AND);
831 }
832 
833 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
834                   void *buffer, size_t *lenp)
835 {
836         int *i, *min, *max, vleft, first=1, len, left, neg, val;
837         #define TMPBUFLEN 20
838         char buf[TMPBUFLEN], *p;
839         
840         if (!table->data || !table->maxlen || !*lenp ||
841             (filp->f_pos && !write)) {
842                 *lenp = 0;
843                 return 0;
844         }
845         
846         i = (int *) table->data;
847         min = (int *) table->extra1;
848         max = (int *) table->extra2;
849         vleft = table->maxlen / sizeof(int);
850         left = *lenp;
851         
852         for (; left && vleft--; i++, first=0) {
853                 if (write) {
854                         while (left) {
855                                 char c;
856                                 if(get_user(c, (char *) buffer))
857                                         return -EFAULT;
858                                 if (!isspace(c))
859                                         break;
860                                 left--;
861                                 ((char *) buffer)++;
862                         }
863                         if (!left)
864                                 break;
865                         neg = 0;
866                         len = left;
867                         if (len > TMPBUFLEN-1)
868                                 len = TMPBUFLEN-1;
869                         if(copy_from_user(buf, buffer, len))
870                                 return -EFAULT;
871                         buf[len] = 0;
872                         p = buf;
873                         if (*p == '-' && left > 1) {
874                                 neg = 1;
875                                 left--, p++;
876                         }
877                         if (*p < '' || *p > '9')
878                                 break;
879                         val = simple_strtoul(p, &p, 0);
880                         len = p-buf;
881                         if ((len < left) && *p && !isspace(*p))
882                                 break;
883                         if (neg)
884                                 val = -val;
885                         buffer += len;
886                         left -= len;
887 
888                         if (min && val < *min++)
889                                 continue;
890                         if (max && val > *max++)
891                                 continue;
892                         *i = val;
893                 } else {
894                         p = buf;
895                         if (!first)
896                                 *p++ = '\t';
897                         sprintf(p, "%d", *i);
898                         len = strlen(buf);
899                         if (len > left)
900                                 len = left;
901                         if(copy_to_user(buffer, buf, len))
902                                 return -EFAULT;
903                         left -= len;
904                         buffer += len;
905                 }
906         }
907 
908         if (!write && !first && left) {
909                 if(put_user('\n', (char *) buffer))
910                         return -EFAULT;
911                 left--, buffer++;
912         }
913         if (write) {
914                 p = (char *) buffer;
915                 while (left) {
916                         char c;
917                         if(get_user(c, p++))
918                                 return -EFAULT;
919                         if (!isspace(c))
920                                 break;
921                         left--;
922                 }
923         }
924         if (write && first)
925                 return -EINVAL;
926         *lenp -= left;
927         filp->f_pos += *lenp;
928         return 0;
929 }
930 
931 /*
932  * an unsigned long function version
933  */
934 
935 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
936                                      struct file *filp,
937                                      void *buffer, size_t *lenp,
938                                      unsigned long convmul,
939                                      unsigned long convdiv)
940 {
941 #define TMPBUFLEN 20
942         unsigned long *i, *min, *max, val;
943         int vleft, first=1, len, left, neg;
944         char buf[TMPBUFLEN], *p;
945         
946         if (!table->data || !table->maxlen || !*lenp ||
947             (filp->f_pos && !write)) {
948                 *lenp = 0;
949                 return 0;
950         }
951         
952         i = (unsigned long *) table->data;
953         min = (unsigned long *) table->extra1;
954         max = (unsigned long *) table->extra2;
955         vleft = table->maxlen / sizeof(unsigned long);
956         left = *lenp;
957         
958         for (; left && vleft--; i++, first=0) {
959                 if (write) {
960                         while (left) {
961                                 char c;
962                                 if(get_user(c, (char *) buffer))
963                                         return -EFAULT;
964                                 if (!isspace(c))
965                                         break;
966                                 left--;
967                                 ((char *) buffer)++;
968                         }
969                         if (!left)
970                                 break;
971                         neg = 0;
972                         len = left;
973                         if (len > TMPBUFLEN-1)
974                                 len = TMPBUFLEN-1;
975                         if(copy_from_user(buf, buffer, len))
976                                 return -EFAULT;
977                         buf[len] = 0;
978                         p = buf;
979                         if (*p == '-' && left > 1) {
980                                 neg = 1;
981                                 left--, p++;
982                         }
983                         if (*p < '' || *p > '9')
984                                 break;
985                         val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
986                         len = p-buf;
987                         if ((len < left) && *p && !isspace(*p))
988                                 break;
989                         if (neg)
990                                 val = -val;
991                         buffer += len;
992                         left -= len;
993 
994                         if(neg)
995                                 continue;
996                         if (min && val < *min++)
997                                 continue;
998                         if (max && val > *max++)
999                                 continue;
1000                         *i = val;
1001                 } else {
1002                         p = buf;
1003                         if (!first)
1004                                 *p++ = '\t';
1005                         sprintf(p, "%lu", convdiv * (*i) / convmul);
1006                         len = strlen(buf);
1007                         if (len > left)
1008                                 len = left;
1009                         if(copy_to_user(buffer, buf, len))
1010                                 return -EFAULT;
1011                         left -= len;
1012                         buffer += len;
1013                 }
1014         }
1015 
1016         if (!write && !first && left) {
1017                 if(put_user('\n', (char *) buffer))
1018                         return -EFAULT;
1019                 left--, buffer++;
1020         }
1021         if (write) {
1022                 p = (char *) buffer;
1023                 while (left) {
1024                         char c;
1025                         if(get_user(c, p++))
1026                                 return -EFAULT;
1027                         if (!isspace(c))
1028                                 break;
1029                         left--;
1030                 }
1031         }
1032         if (write && first)
1033                 return -EINVAL;
1034         *lenp -= left;
1035         filp->f_pos += *lenp;
1036         return 0;
1037 #undef TMPBUFLEN
1038 }
1039 
1040 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1041                            void *buffer, size_t *lenp)
1042 {
1043     return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1044 }
1045 
1046 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1047                                       struct file *filp,
1048                                       void *buffer, size_t *lenp)
1049 {
1050     return do_proc_doulongvec_minmax(table, write, filp, buffer,
1051                                      lenp, HZ, 1000l);
1052 }
1053 
1054 
1055 /* Like proc_dointvec, but converts seconds to jiffies */
1056 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1057                           void *buffer, size_t *lenp)
1058 {
1059     return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1060 }
1061 
1062 #else /* CONFIG_PROC_FS */
1063 
1064 int proc_dostring(ctl_table *table, int write, struct file *filp,
1065                   void *buffer, size_t *lenp)
1066 {
1067         return -ENOSYS;
1068 }
1069 
1070 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1071                             void *buffer, size_t *lenp)
1072 {
1073         return -ENOSYS;
1074 }
1075 
1076 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1077                   void *buffer, size_t *lenp)
1078 {
1079         return -ENOSYS;
1080 }
1081 
1082 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1083                         void *buffer, size_t *lenp)
1084 {
1085         return -ENOSYS;
1086 }
1087 
1088 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1089                     void *buffer, size_t *lenp)
1090 {
1091         return -ENOSYS;
1092 }
1093 
1094 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1095                     void *buffer, size_t *lenp)
1096 {
1097         return -ENOSYS;
1098 }
1099 
1100 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1101                     void *buffer, size_t *lenp)
1102 {
1103         return -ENOSYS;
1104 }
1105 
1106 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1107                                       struct file *filp,
1108                                       void *buffer, size_t *lenp)
1109 {
1110     return -ENOSYS;
1111 }
1112 
1113 
1114 #endif /* CONFIG_PROC_FS */
1115 
1116 
1117 /*
1118  * General sysctl support routines 
1119  */
1120 
1121 /* The generic string strategy routine: */
1122 int sysctl_string(ctl_table *table, int *name, int nlen,
1123                   void *oldval, size_t *oldlenp,
1124                   void *newval, size_t newlen, void **context)
1125 {
1126         int l, len;
1127         
1128         if (!table->data || !table->maxlen) 
1129                 return -ENOTDIR;
1130         
1131         if (oldval && oldlenp) {
1132                 if(get_user(len, oldlenp))
1133                         return -EFAULT;
1134                 if (len) {
1135                         l = strlen(table->data);
1136                         if (len > l) len = l;
1137                         if (len >= table->maxlen)
1138                                 len = table->maxlen;
1139                         if(copy_to_user(oldval, table->data, len))
1140                                 return -EFAULT;
1141                         if(put_user(0, ((char *) oldval) + len))
1142                                 return -EFAULT;
1143                         if(put_user(len, oldlenp))
1144                                 return -EFAULT;
1145                 }
1146         }
1147         if (newval && newlen) {
1148                 len = newlen;
1149                 if (len > table->maxlen)
1150                         len = table->maxlen;
1151                 if(copy_from_user(table->data, newval, len))
1152                         return -EFAULT;
1153                 if (len == table->maxlen)
1154                         len--;
1155                 ((char *) table->data)[len] = 0;
1156         }
1157         return 0;
1158 }
1159 
1160 /*
1161  * This function makes sure that all of the integers in the vector
1162  * are between the minimum and maximum values given in the arrays
1163  * table->extra1 and table->extra2, respectively.
1164  */
1165 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1166                 void *oldval, size_t *oldlenp,
1167                 void *newval, size_t newlen, void **context)
1168 {
1169         int i, length, *vec, *min, *max;
1170 
1171         if (newval && newlen) {
1172                 if (newlen % sizeof(int) != 0)
1173                         return -EINVAL;
1174 
1175                 if (!table->extra1 && !table->extra2)
1176                         return 0;
1177 
1178                 if (newlen > table->maxlen)
1179                         newlen = table->maxlen;
1180                 length = newlen / sizeof(int);
1181 
1182                 vec = (int *) newval;
1183                 min = (int *) table->extra1;
1184                 max = (int *) table->extra2;
1185 
1186                 for (i = 0; i < length; i++) {
1187                         int value;
1188                         get_user(value, vec + i);
1189                         if (min && value < min[i])
1190                                 return -EINVAL;
1191                         if (max && value > max[i])
1192                                 return -EINVAL;
1193                 }
1194         }
1195         return 0;
1196 }
1197 
1198 /* Strategy function to convert jiffies to seconds */ 
1199 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1200                 void *oldval, size_t *oldlenp,
1201                 void *newval, size_t newlen, void **context)
1202 {
1203         if (oldval) {
1204                 size_t olen;
1205                 if (oldlenp) { 
1206                         if (get_user(olen, oldlenp))
1207                                 return -EFAULT;
1208                         if (olen!=sizeof(int))
1209                                 return -EINVAL; 
1210                 }
1211                 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) || 
1212                     (oldlenp && put_user(sizeof(int),oldlenp)))
1213                         return -EFAULT;
1214         }
1215         if (newval && newlen) { 
1216                 int new;
1217                 if (newlen != sizeof(int))
1218                         return -EINVAL; 
1219                 if (get_user(new, (int *)newval))
1220                         return -EFAULT;
1221                 *(int *)(table->data) = new*HZ; 
1222         }
1223         return 1;
1224 }
1225 
1226 
1227 #else /* CONFIG_SYSCTL */
1228 
1229 
1230 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1231 {
1232         return -ENOSYS;
1233 }
1234 
1235 int sysctl_string(ctl_table *table, int *name, int nlen,
1236                   void *oldval, size_t *oldlenp,
1237                   void *newval, size_t newlen, void **context)
1238 {
1239         return -ENOSYS;
1240 }
1241 
1242 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1243                 void *oldval, size_t *oldlenp,
1244                 void *newval, size_t newlen, void **context)
1245 {
1246         return -ENOSYS;
1247 }
1248 
1249 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1250                 void *oldval, size_t *oldlenp,
1251                 void *newval, size_t newlen, void **context)
1252 {
1253         return -ENOSYS;
1254 }
1255 
1256 int proc_dostring(ctl_table *table, int write, struct file *filp,
1257                   void *buffer, size_t *lenp)
1258 {
1259         return -ENOSYS;
1260 }
1261 
1262 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1263                   void *buffer, size_t *lenp)
1264 {
1265         return -ENOSYS;
1266 }
1267 
1268 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1269                         void *buffer, size_t *lenp)
1270 {
1271         return -ENOSYS;
1272 }
1273 
1274 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1275                     void *buffer, size_t *lenp)
1276 {
1277         return -ENOSYS;
1278 }
1279 
1280 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1281                           void *buffer, size_t *lenp)
1282 {
1283         return -ENOSYS;
1284 }
1285 
1286 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1287                     void *buffer, size_t *lenp)
1288 {
1289         return -ENOSYS;
1290 }
1291 
1292 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1293                                       struct file *filp,
1294                                       void *buffer, size_t *lenp)
1295 {
1296     return -ENOSYS;
1297 }
1298 
1299 struct ctl_table_header * register_sysctl_table(ctl_table * table, 
1300                                                 int insert_at_head)
1301 {
1302         return 0;
1303 }
1304 
1305 void unregister_sysctl_table(struct ctl_table_header * table)
1306 {
1307 }
1308 
1309 #endif /* CONFIG_SYSCTL */
1310 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.