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 Horn.
  12 */
  13
  14#include <linux/config.h>
  15#include <linux/sched.h>
  16#include <linux/mm.h>
  17#include <linux/sysctl.h>
  18#include <linux/swapctl.h>
  19#include <linux/proc_fs.h>
  20#include <linux/malloc.h>
  21#include <linux/stat.h>
  22#include <linux/ctype.h>
  23#include <linux/utsname.h>
  24#include <linux/swapctl.h>
  25#include <linux/smp.h>
  26#include <linux/smp_lock.h>
  27#include <linux/init.h>
  28
  29#include <asm/bitops.h>
  30#include <asm/uaccess.h>
  31
  32#ifdef CONFIG_ROOT_NFS
  33#include <linux/nfs_fs.h>
  34#endif
  35
  36#ifdef CONFIG_SYSCTL
  37
  38/* External variables not in a header file. */
  39extern int panic_timeout;
  40extern int console_loglevel, C_A_D, swapout_interval;
  41extern int bdf_prm[], bdflush_min[], bdflush_max[];
  42extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
  43extern int sysctl_overcommit_memory;
  44
  45#ifdef __sparc__
  46extern char reboot_command [];
  47#endif
  48
  49static int parse_table(int *, int, void *, size_t *, void *, size_t,
  50                       ctl_table *, void **);
  51static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
  52                                    void *, size_t, void **);
  53
  54
  55static ctl_table root_table[];
  56static struct ctl_table_header root_table_header = 
  57        {root_table, DNODE_SINGLE(&root_table_header)};
  58
  59static ctl_table kern_table[];
  60static ctl_table vm_table[];
  61extern ctl_table net_table[];
  62static ctl_table proc_table[];
  63static ctl_table fs_table[];
  64static ctl_table debug_table[];
  65static ctl_table dev_table[];
  66
  67
  68/* /proc declarations: */
  69
  70#ifdef CONFIG_PROC_FS
  71
  72static long proc_readsys(struct inode * inode, struct file * file,
  73                        char * buf, unsigned long count);
  74static long proc_writesys(struct inode * inode, struct file * file,
  75                         const char * buf, unsigned long count);
  76static int proc_sys_permission(struct inode *, int);
  77
  78struct file_operations proc_sys_file_operations =
  79{
  80        NULL,           /* lseek   */
  81        proc_readsys,   /* read    */
  82        proc_writesys,  /* write   */
  83        NULL,           /* readdir */
  84        NULL,           /* poll    */
  85        NULL,           /* ioctl   */
  86        NULL,           /* mmap    */
  87        NULL,           /* no special open code    */
  88        NULL,           /* no special release code */
  89        NULL            /* can't fsync */
  90};
  91
  92struct inode_operations proc_sys_inode_operations =
  93{
  94        &proc_sys_file_operations,
  95        NULL,           /* create */
  96        NULL,           /* lookup */
  97        NULL,           /* link */
  98        NULL,           /* unlink */
  99        NULL,           /* symlink */
 100        NULL,           /* mkdir */
 101        NULL,           /* rmdir */
 102        NULL,           /* mknod */
 103        NULL,           /* rename */
 104        NULL,           /* readlink */
 105        NULL,           /* follow_link */
 106        NULL,           /* readpage */
 107        NULL,           /* writepage */
 108        NULL,           /* bmap */
 109        NULL,           /* truncate */
 110        proc_sys_permission
 111};
 112
 113extern struct proc_dir_entry proc_sys_root;
 114
 115extern int inodes_stat[];
 116static void register_proc_table(ctl_table *, struct proc_dir_entry *);
 117static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
 118#endif
 119
 120/* The default sysctl tables: */
 121
 122static ctl_table root_table[] = {
 123        {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
 124        {CTL_VM, "vm", NULL, 0, 0555, vm_table},
 125        {CTL_NET, "net", NULL, 0, 0555, net_table},
 126        {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
 127        {CTL_FS, "fs", NULL, 0, 0555, fs_table},
 128        {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
 129        {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
 130        {0}
 131};
 132
 133static ctl_table kern_table[] = {
 134        {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
 135         0444, NULL, &proc_dostring, &sysctl_string},
 136        {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
 137         0444, NULL, &proc_dostring, &sysctl_string},
 138        {KERN_VERSION, "version", system_utsname.version, 64,
 139         0444, NULL, &proc_dostring, &sysctl_string},
 140        {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
 141         0644, NULL, &proc_dostring, &sysctl_string},
 142        {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
 143         0644, NULL, &proc_dostring, &sysctl_string},
 144        {KERN_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
 145         0444, NULL, &proc_dointvec},
 146        {KERN_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
 147         0444, NULL, &proc_dointvec},
 148        {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
 149         0644, NULL, &proc_dointvec},
 150        {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
 151         0444, NULL, &proc_dointvec},
 152        {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
 153         0644, NULL, &proc_dointvec},
 154        {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
 155         0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
 156        {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 157         0644, NULL, &proc_dointvec},
 158#ifdef CONFIG_BLK_DEV_INITRD
 159        {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
 160         0644, NULL, &proc_dointvec},
 161#endif
 162#ifdef CONFIG_ROOT_NFS
 163        {KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
 164         0644, NULL, &proc_dostring, &sysctl_string },
 165        {KERN_NFSRADDRS, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
 166         0644, NULL, &proc_dostring, &sysctl_string },
 167#endif
 168#ifdef CONFIG_BINFMT_JAVA
 169        {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
 170         64, 0644, NULL, &proc_dostring, &sysctl_string },
 171        {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
 172         64, 0644, NULL, &proc_dostring, &sysctl_string },
 173#endif
 174#ifdef __sparc__
 175        {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
 176         256, 0644, NULL, &proc_dostring, &sysctl_string },
 177#endif
 178        {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
 179         0644, NULL, &proc_dointvec},
 180        {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
 181         0644, NULL, &proc_dointvec},
 182        {0}
 183};
 184
 185static ctl_table vm_table[] = {
 186        {VM_SWAPCTL, "swapctl", 
 187         &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
 188        {VM_SWAPOUT, "swapout_interval",
 189         &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies},
 190        {VM_FREEPG, "freepages", 
 191         &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
 192        {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
 193         &proc_dointvec_minmax, &sysctl_intvec, NULL,
 194         &bdflush_min, &bdflush_max},
 195        {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
 196         sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
 197        {0}
 198};
 199
 200static ctl_table proc_table[] = {
 201        {0}
 202};
 203
 204static ctl_table fs_table[] = {
 205        {0}
 206};
 207
 208static ctl_table debug_table[] = {
 209        {0}
 210};
 211
 212static ctl_table dev_table[] = {
 213        {0}
 214};  
 215
 216
 217__initfunc(void sysctl_init(void))
 218{
 219#ifdef CONFIG_PROC_FS
 220        register_proc_table(root_table, &proc_sys_root);
 221#endif
 222}
 223
 224
 225int do_sysctl (int *name, int nlen,
 226               void *oldval, size_t *oldlenp,
 227               void *newval, size_t newlen)
 228{
 229        int error;
 230        struct ctl_table_header *tmp;
 231        void *context;
 232        
 233        if (nlen == 0 || nlen >= CTL_MAXNAME)
 234                return -ENOTDIR;
 235        
 236        if (oldval) 
 237        {
 238                int old_len;
 239                if (!oldlenp)
 240                        return -EFAULT;
 241                if(get_user(old_len, oldlenp))
 242                        return -EFAULT;
 243        }
 244        tmp = &root_table_header;
 245        do {
 246                context = NULL;
 247                error = parse_table(name, nlen, oldval, oldlenp, 
 248                                    newval, newlen, tmp->ctl_table, &context);
 249                if (context)
 250                        kfree(context);
 251                if (error != -ENOTDIR)
 252                        return error;
 253                tmp = tmp->DLIST_NEXT(ctl_entry);
 254        } while (tmp != &root_table_header);
 255        return -ENOTDIR;
 256}
 257
 258extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
 259{
 260        struct __sysctl_args tmp;
 261        int error;
 262
 263        if(copy_from_user(&tmp, args, sizeof(tmp)))
 264                return -EFAULT;
 265                
 266        lock_kernel();
 267        error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
 268                          tmp.newval, tmp.newlen);
 269        unlock_kernel();
 270        return error;
 271}
 272
 273/* Like in_group_p, but testing against egid, not fsgid */
 274static int in_egroup_p(gid_t grp)
 275{
 276        if (grp != current->egid) {
 277                int i = current->ngroups;
 278                if (i) {
 279                        gid_t *groups = current->groups;
 280                        do {
 281                                if (*groups == grp)
 282                                        goto out;
 283                                groups++;
 284                                i--;
 285                        } while (i);
 286                }
 287                return 0;
 288        }
 289out:
 290        return 1;
 291}
 292
 293/* ctl_perm does NOT grant the superuser all rights automatically, because
 294   some sysctl variables are readonly even to root. */
 295
 296static int test_perm(int mode, int op)
 297{
 298        if (!current->euid)
 299                mode >>= 6;
 300        else if (in_egroup_p(0))
 301                mode >>= 3;
 302        if ((mode & op & 0007) == op)
 303                return 0;
 304        return -EACCES;
 305}
 306
 307static inline int ctl_perm(ctl_table *table, int op)
 308{
 309        return test_perm(table->mode, op);
 310}
 311
 312static int parse_table(int *name, int nlen,
 313                       void *oldval, size_t *oldlenp,
 314                       void *newval, size_t newlen,
 315                       ctl_table *table, void **context)
 316{
 317        int error;
 318repeat:
 319        if (!nlen)
 320                return -ENOTDIR;
 321
 322        for ( ; table->ctl_name; table++) {
 323                int n;
 324                if(get_user(n,name))
 325                        return -EFAULT;
 326                if (n == table->ctl_name ||
 327                    table->ctl_name == CTL_ANY) {
 328                        if (table->child) {
 329                                if (ctl_perm(table, 001))
 330                                        return -EPERM;
 331                                if (table->strategy) {
 332                                        error = table->strategy(
 333                                                table, name, nlen,
 334                                                oldval, oldlenp,
 335                                                newval, newlen, context);
 336                                if (error)
 337                                        return error;
 338                                }
 339                                name++;
 340                                nlen--;
 341                                table = table->child;
 342                                goto repeat;
 343                        }
 344                        error = do_sysctl_strategy(table, name, nlen,
 345                                                   oldval, oldlenp,
 346                                                   newval, newlen, context);
 347                        return error;
 348                }
 349        };
 350        return -ENOTDIR;
 351}
 352
 353/* Perform the actual read/write of a sysctl table entry. */
 354int do_sysctl_strategy (ctl_table *table, 
 355                        int *name, int nlen,
 356                        void *oldval, size_t *oldlenp,
 357                        void *newval, size_t newlen, void **context)
 358{
 359        int op = 0, rc, len;
 360
 361        if (oldval)
 362                op |= 004;
 363        if (newval) 
 364                op |= 002;
 365        if (ctl_perm(table, op))
 366                return -EPERM;
 367
 368        if (table->strategy) {
 369                rc = table->strategy(table, name, nlen, oldval, oldlenp,
 370                                     newval, newlen, context);
 371                if (rc < 0)
 372                        return rc;
 373                if (rc > 0)
 374                        return 0;
 375        }
 376
 377        /* If there is no strategy routine, or if the strategy returns
 378         * zero, proceed with automatic r/w */
 379        if (table->data && table->maxlen) {
 380                if (oldval && oldlenp) {
 381                        get_user(len, oldlenp);
 382                        if (len) {
 383                                if (len > table->maxlen)
 384                                        len = table->maxlen;
 385                                if(copy_to_user(oldval, table->data, len))
 386                                        return -EFAULT;
 387                                if(put_user(len, oldlenp))
 388                                        return -EFAULT;
 389                        }
 390                }
 391                if (newval && newlen) {
 392                        len = newlen;
 393                        if (len > table->maxlen)
 394                                len = table->maxlen;
 395                        if(copy_from_user(table->data, newval, len))
 396                                return -EFAULT;
 397                }
 398        }
 399        return 0;
 400}
 401
 402/*
 403 * This function only checks permission for changing the security level
 404 * If the tests are successful, the actual change is done by
 405 * do_sysctl_strategy
 406 */
 407static int do_securelevel_strategy (ctl_table *table, 
 408                                    int *name, int nlen,
 409                                    void *oldval, size_t *oldlenp,
 410                                    void *newval, size_t newlen, void **context)
 411{
 412        int level;
 413
 414        if (newval && newlen) {
 415                if (newlen != sizeof (int))
 416                        return -EINVAL;
 417                if(copy_from_user (&level, newval, newlen))
 418                        return -EFAULT;
 419                if (level < securelevel && current->pid != 1)
 420                        return -EPERM;
 421        }
 422        return 0;
 423}
 424
 425struct ctl_table_header *register_sysctl_table(ctl_table * table, 
 426                                               int insert_at_head)
 427{
 428        struct ctl_table_header *tmp;
 429        tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
 430        if (!tmp)
 431                return 0;
 432        *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
 433        if (insert_at_head)
 434                DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
 435        else
 436                DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
 437#ifdef CONFIG_PROC_FS
 438        register_proc_table(table, &proc_sys_root);
 439#endif
 440        return tmp;
 441}
 442
 443void unregister_sysctl_table(struct ctl_table_header * table)
 444{
 445        DLIST_DELETE(table, ctl_entry);
 446#ifdef CONFIG_PROC_FS
 447        unregister_proc_table(table->ctl_table, &proc_sys_root);
 448#endif
 449}
 450
 451/*
 452 * /proc/sys support
 453 */
 454
 455#ifdef CONFIG_PROC_FS
 456
 457/* Scan the sysctl entries in table and add them all into /proc */
 458static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
 459{
 460        struct proc_dir_entry *de;
 461        int len;
 462        mode_t mode;
 463        
 464        for (; table->ctl_name; table++) {
 465                de = 0;
 466                /* Can't do anything without a proc name. */
 467                if (!table->procname)
 468                        continue;
 469                /* Maybe we can't do anything with it... */
 470                if (!table->proc_handler &&
 471                    !table->child)
 472                        continue;
 473
 474                len = strlen(table->procname);
 475                mode = table->mode;
 476
 477                if (table->proc_handler)
 478                        mode |= S_IFREG;
 479                else {
 480                        mode |= S_IFDIR;
 481                        for (de = root->subdir; de; de = de->next) {
 482                                if (proc_match(len, table->procname, de))
 483                                        break;
 484                        }
 485                        /* If the subdir exists already, de is non-NULL */
 486                }
 487
 488                if (!de) {
 489                        de = create_proc_entry(table->procname, mode, root);
 490                        if (!de)
 491                                continue;
 492                        de->data = (void *) table;
 493                        if (table->proc_handler)
 494                                de->ops = &proc_sys_inode_operations;
 495
 496                }
 497                table->de = de;
 498                if (de->mode & S_IFDIR)
 499                        register_proc_table(table->child, de);
 500        }
 501}
 502
 503static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
 504{
 505        struct proc_dir_entry *de;
 506        for (; table->ctl_name; table++) {
 507                if (!(de = table->de))
 508                        continue;
 509                if (de->mode & S_IFDIR) {
 510                        if (!table->child) {
 511                                printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
 512                                continue;
 513                        }
 514                        unregister_proc_table(table->child, de);
 515                }
 516                /* Don't unregister proc directories which still have
 517                   entries... */
 518                if (!((de->mode & S_IFDIR) && de->subdir)) {
 519                        proc_unregister(root, de->low_ino);
 520                        kfree(de);
 521                }
 522        }
 523}
 524
 525
 526static long do_rw_proc(int write, struct inode * inode, struct file * file,
 527                      char * buf, unsigned long count)
 528{
 529        int op;
 530        struct proc_dir_entry *de;
 531        struct ctl_table *table;
 532        size_t res;
 533        long error;
 534        
 535        de = (struct proc_dir_entry*) inode->u.generic_ip;
 536        if (!de || !de->data)
 537                return -ENOTDIR;
 538        table = (struct ctl_table *) de->data;
 539        if (!table || !table->proc_handler)
 540                return -ENOTDIR;
 541        op = (write ? 002 : 004);
 542        if (ctl_perm(table, op))
 543                return -EPERM;
 544        
 545        res = count;
 546        error = (*table->proc_handler) (table, write, file, buf, &res);
 547        if (error)
 548                return error;
 549        return res;
 550}
 551
 552static long proc_readsys(struct inode * inode, struct file * file,
 553                        char * buf, unsigned long count)
 554{
 555        return do_rw_proc(0, inode, file, buf, count);
 556}
 557
 558static long proc_writesys(struct inode * inode, struct file * file,
 559                         const char * buf, unsigned long count)
 560{
 561        return do_rw_proc(1, inode, file, (char *) buf, count);
 562}
 563
 564static int proc_sys_permission(struct inode *inode, int op)
 565{
 566        return test_perm(inode->i_mode, op);
 567}
 568
 569int proc_dostring(ctl_table *table, int write, struct file *filp,
 570                  void *buffer, size_t *lenp)
 571{
 572        int len;
 573        char *p, c;
 574        
 575        if (!table->data || !table->maxlen || !*lenp ||
 576            (filp->f_pos && !write)) {
 577                *lenp = 0;
 578                return 0;
 579        }
 580        
 581        if (write) {
 582                len = 0;
 583                p = buffer;
 584                while (len < *lenp) {
 585                        if(get_user(c, p++))
 586                                return -EFAULT;
 587                        if (c == 0 || c == '\n')
 588                                break;
 589                        len++;
 590                }
 591                if (len >= table->maxlen)
 592                        len = table->maxlen-1;
 593                if(copy_from_user(table->data, buffer, len))
 594                        return -EFAULT;
 595                ((char *) table->data)[len] = 0;
 596                filp->f_pos += *lenp;
 597        } else {
 598                len = strlen(table->data);
 599                if (len > table->maxlen)
 600                        len = table->maxlen;
 601                if (len > *lenp)
 602                        len = *lenp;
 603                if (len)
 604                        if(copy_to_user(buffer, table->data, len))
 605                                return -EFAULT;
 606                if (len < *lenp) {
 607                        if(put_user('\n', ((char *) buffer) + len))
 608                                return -EFAULT;
 609                        len++;
 610                }
 611                *lenp = len;
 612                filp->f_pos += len;
 613        }
 614        return 0;
 615}
 616
 617static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
 618                  void *buffer, size_t *lenp, int conv)
 619{
 620        int *i, vleft, first=1, len, left, neg, val;
 621        #define TMPBUFLEN 20
 622        char buf[TMPBUFLEN], *p;
 623        
 624        if (!table->data || !table->maxlen || !*lenp ||
 625            (filp->f_pos && !write)) {
 626                *lenp = 0;
 627                return 0;
 628        }
 629        
 630        i = (int *) table->data;
 631        vleft = table->maxlen / sizeof(int);
 632        left = *lenp;
 633        
 634        for (; left && vleft--; i++, first=0) {
 635                if (write) {
 636                        while (left) {
 637                                char c;
 638                                if(get_user(c,(char *) buffer))
 639                                        return -EFAULT;
 640                                if (!isspace(c))
 641                                        break;
 642                                left--;
 643                                ((char *) buffer)++;
 644                        }
 645                        if (!left)
 646                                break;
 647                        neg = 0;
 648                        len = left;
 649                        if (len > TMPBUFLEN-1)
 650                                len = TMPBUFLEN-1;
 651                        if(copy_from_user(buf, buffer, len))
 652                                return -EFAULT;
 653                        buf[len] = 0;
 654                        p = buf;
 655                        if (*p == '-' && left > 1) {
 656                                neg = 1;
 657                                left--, p++;
 658                        }
 659                        if (*p < '0' || *p > '9')
 660                                break;
 661                        val = simple_strtoul(p, &p, 0) * conv;
 662                        len = p-buf;
 663                        if ((len < left) && *p && !isspace(*p))
 664                                break;
 665                        if (neg)
 666                                val = -val;
 667                        buffer += len;
 668                        left -= len;
 669                        *i = val;
 670                } else {
 671                        p = buf;
 672                        if (!first)
 673                                *p++ = '\t';
 674                        sprintf(p, "%d", (*i) / conv);
 675                        len = strlen(buf);
 676                        if (len > left)
 677                                len = left;
 678                        if(copy_to_user(buffer, buf, len))
 679                                return -EFAULT;
 680                        left -= len;
 681                        buffer += len;
 682                }
 683        }
 684
 685        if (!write && !first && left) {
 686                if(put_user('\n', (char *) buffer))
 687                        return -EFAULT;
 688                left--, buffer++;
 689        }
 690        if (write) {
 691                p = (char *) buffer;
 692                while (left) {
 693                        char c;
 694                        if(get_user(c, p++))
 695                                return -EFAULT;
 696                        if (!isspace(c))
 697                                break;
 698                        left--;
 699                }
 700        }
 701        if (write && first)
 702                return -EINVAL;
 703        *lenp -= left;
 704        filp->f_pos += *lenp;
 705        return 0;
 706}
 707
 708int proc_dointvec(ctl_table *table, int write, struct file *filp,
 709                     void *buffer, size_t *lenp)
 710{
 711    return do_proc_dointvec(table,write,filp,buffer,lenp,1);
 712}
 713
 714int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
 715                  void *buffer, size_t *lenp)
 716{
 717        int *i, *min, *max, vleft, first=1, len, left, neg, val;
 718        #define TMPBUFLEN 20
 719        char buf[TMPBUFLEN], *p;
 720        
 721        if (!table->data || !table->maxlen || !*lenp ||
 722            (filp->f_pos && !write)) {
 723                *lenp = 0;
 724                return 0;
 725        }
 726        
 727        i = (int *) table->data;
 728        min = (int *) table->extra1;
 729        max = (int *) table->extra2;
 730        vleft = table->maxlen / sizeof(int);
 731        left = *lenp;
 732        
 733        for (; left && vleft--; i++, first=0) {
 734                if (write) {
 735                        while (left) {
 736                                char c;
 737                                if(get_user(c, (char *) buffer))
 738                                        return -EFAULT;
 739                                if (!isspace(c))
 740                                        break;
 741                                left--;
 742                                ((char *) buffer)++;
 743                        }
 744                        if (!left)
 745                                break;
 746                        neg = 0;
 747                        len = left;
 748                        if (len > TMPBUFLEN-1)
 749                                len = TMPBUFLEN-1;
 750                        if(copy_from_user(buf, buffer, len))
 751                                return -EFAULT;
 752                        buf[len] = 0;
 753                        p = buf;
 754                        if (*p == '-' && left > 1) {
 755                                neg = 1;
 756                                left--, p++;
 757                        }
 758                        if (*p < '0' || *p > '9')
 759                                break;
 760                        val = simple_strtoul(p, &p, 0);
 761                        len = p-buf;
 762                        if ((len < left) && *p && !isspace(*p))
 763                                break;
 764                        if (neg)
 765                                val = -val;
 766                        buffer += len;
 767                        left -= len;
 768
 769                        if (min && val < *min++)
 770                                continue;
 771                        if (max && val > *max++)
 772                                continue;
 773                        *i = val;
 774                } else {
 775                        p = buf;
 776                        if (!first)
 777                                *p++ = '\t';
 778                        sprintf(p, "%d", *i);
 779                        len = strlen(buf);
 780                        if (len > left)
 781                                len = left;
 782                        if(copy_to_user(buffer, buf, len))
 783                                return -EFAULT;
 784                        left -= len;
 785                        buffer += len;
 786                }
 787        }
 788
 789        if (!write && !first && left) {
 790                if(put_user('\n', (char *) buffer))
 791                        return -EFAULT;
 792                left--, buffer++;
 793        }
 794        if (write) {
 795                p = (char *) buffer;
 796                while (left) {
 797                        char c;
 798                        if(get_user(c, p++))
 799                                return -EFAULT;
 800                        if (!isspace(c))
 801                                break;
 802                        left--;
 803                }
 804        }
 805        if (write && first)
 806                return -EINVAL;
 807        *lenp -= left;
 808        filp->f_pos += *lenp;
 809        return 0;
 810}
 811
 812/* Like proc_dointvec, but converts seconds to jiffies */
 813int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
 814                          void *buffer, size_t *lenp)
 815{
 816    return do_proc_dointvec(table,write,filp,buffer,lenp,HZ);
 817}
 818
 819#else /* CONFIG_PROC_FS */
 820
 821int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
 822                          void *buffer, size_t *lenp)
 823{
 824  return -ENOSYS; 
 825}
 826
 827int proc_dostring(ctl_table *table, int write, struct file *filp,
 828                  void *buffer, size_t *lenp)
 829{
 830        return -ENOSYS;
 831}
 832
 833int proc_dointvec(ctl_table *table, int write, struct file *filp,
 834                  void *buffer, size_t *lenp)
 835{
 836        return -ENOSYS;
 837}
 838
 839int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
 840                    void *buffer, size_t *lenp)
 841{
 842        return -ENOSYS;
 843}
 844
 845int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
 846                    void *buffer, size_t *lenp)
 847{
 848        return -ENOSYS;
 849}
 850
 851#endif /* CONFIG_PROC_FS */
 852
 853
 854/*
 855 * General sysctl support routines 
 856 */
 857
 858/* The generic string strategy routine: */
 859int sysctl_string(ctl_table *table, int *name, int nlen,
 860                  void *oldval, size_t *oldlenp,
 861                  void *newval, size_t newlen, void **context)
 862{
 863        int l, len;
 864        
 865        if (!table->data || !table->maxlen) 
 866                return -ENOTDIR;
 867        
 868        if (oldval && oldlenp) {
 869                if(get_user(len, oldlenp))
 870                        return -EFAULT;
 871                if (len) {
 872                        l = strlen(table->data);
 873                        if (len > l) len = l;
 874                        if (len >= table->maxlen)
 875                                len = table->maxlen;
 876                        if(copy_to_user(oldval, table->data, len))
 877                                return -EFAULT;
 878                        if(put_user(0, ((char *) oldval) + len))
 879                                return -EFAULT;
 880                        if(put_user(len, oldlenp))
 881                                return -EFAULT;
 882                }
 883        }
 884        if (newval && newlen) {
 885                len = newlen;
 886                if (len > table->maxlen)
 887                        len = table->maxlen;
 888                if(copy_from_user(table->data, newval, len))
 889                        return -EFAULT;
 890                if (len == table->maxlen)
 891                        len--;
 892                ((char *) table->data)[len] = 0;
 893#ifdef CONFIG_TRANS_NAMES
 894                translations_dirty = 1;
 895#endif
 896        }
 897        return 0;
 898}
 899
 900/*
 901 * This function makes sure that all of the integers in the vector
 902 * are between the minimum and maximum values given in the arrays
 903 * table->extra1 and table->extra2, respectively.
 904 */
 905int sysctl_intvec(ctl_table *table, int *name, int nlen,
 906                void *oldval, size_t *oldlenp,
 907                void *newval, size_t newlen, void **context)
 908{
 909        int i, length, *vec, *min, *max;
 910
 911        if (newval && newlen) {
 912                if (newlen % sizeof(int) != 0)
 913                        return -EINVAL;
 914
 915                if (!table->extra1 && !table->extra2)
 916                        return 0;
 917
 918                if (newlen > table->maxlen)
 919                        newlen = table->maxlen;
 920                length = newlen / sizeof(int);
 921
 922                vec = (int *) newval;
 923                min = (int *) table->extra1;
 924                max = (int *) table->extra2;
 925
 926                for (i = 0; i < length; i++) {
 927                        int value;
 928                        get_user(value, vec + i);
 929                        if (min && value < min[i])
 930                                return -EINVAL;
 931                        if (max && value > max[i])
 932                                return -EINVAL;
 933                }
 934        }
 935        return 0;
 936}
 937
 938int do_string (
 939        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
 940        int rdwr, char *data, size_t max)
 941{
 942        int l = strlen(data) + 1;
 943        if (newval && !rdwr)
 944                return -EPERM;
 945        if (newval && newlen >= max)
 946                return -EINVAL;
 947        if (oldval) {
 948                int old_l;
 949                if(get_user(old_l, oldlenp))
 950                        return -EFAULT;
 951                if (l > old_l)
 952                        return -ENOMEM;
 953                if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
 954                        return -EFAULT;
 955        }
 956        if (newval) {
 957                if(copy_from_user(data, newval, newlen))
 958                        return -EFAULT;
 959                data[newlen] = 0;
 960        }
 961        return 0;
 962}
 963
 964int do_int (
 965        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
 966        int rdwr, int *data)
 967{
 968        if (newval && !rdwr)
 969                return -EPERM;
 970        if (newval && newlen != sizeof(int))
 971                return -EINVAL;
 972        if (oldval) {
 973                int old_l;
 974                if(get_user(old_l, oldlenp))
 975                        return -EFAULT;
 976                if (old_l < sizeof(int))
 977                        return -ENOMEM;
 978                if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
 979                        return -EFAULT;
 980        }
 981        if (newval)
 982                if(copy_from_user(data, newval, sizeof(int)))
 983                        return -EFAULT;
 984        return 0;
 985}
 986
 987int do_struct (
 988        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
 989        int rdwr, void *data, size_t len)
 990{
 991        if (newval && !rdwr)
 992                return -EPERM;
 993        if (newval && newlen != len)
 994                return -EINVAL;
 995        if (oldval) {
 996                int old_l;
 997                if(get_user(old_l, oldlenp))
 998                        return -EFAULT;
 999                if (old_l < len)
1000                        return -ENOMEM;
1001                if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
1002                        return -EFAULT;
1003        }
1004        if (newval)
1005                if(copy_from_user(data, newval, len))
1006                        return -EFAULT;
1007        return 0;
1008}
1009
1010
1011#else /* CONFIG_SYSCTL */
1012
1013
1014extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
1015{
1016        return -ENOSYS;
1017}
1018
1019int sysctl_string(ctl_table *table, int *name, int nlen,
1020                  void *oldval, size_t *oldlenp,
1021                  void *newval, size_t newlen, void **context)
1022{
1023        return -ENOSYS;
1024}
1025
1026int sysctl_intvec(ctl_table *table, int *name, int nlen,
1027                void *oldval, size_t *oldlenp,
1028                void *newval, size_t newlen, void **context)
1029{
1030        return -ENOSYS;
1031}
1032
1033int proc_dostring(ctl_table *table, int write, struct file *filp,
1034                  void *buffer, size_t *lenp)
1035{
1036        return -ENOSYS;
1037}
1038
1039int proc_dointvec(ctl_table *table, int write, struct file *filp,
1040                  void *buffer, size_t *lenp)
1041{
1042        return -ENOSYS;
1043}
1044
1045int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1046                    void *buffer, size_t *lenp)
1047{
1048        return -ENOSYS;
1049}
1050
1051int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1052                    void *buffer, size_t *lenp)
1053{
1054        return -ENOSYS;
1055}
1056
1057struct ctl_table_header * register_sysctl_table(ctl_table * table, 
1058                                                int insert_at_head)
1059{
1060        return 0;
1061}
1062
1063void unregister_sysctl_table(struct ctl_table_header * table)
1064{
1065}
1066
1067#endif /* CONFIG_SYSCTL */
1068
1069
1070
1071
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.