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