The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kernel/sysctl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ea82954b11516cb623f69b26ebe8c2b2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.