OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [kernel/] [sysctl.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 * sysctl.c: General linux system control interface
 * sysctl.c: General linux system control interface
 *
 *
 * Begun 24 March 1995, Stephen Tweedie
 * Begun 24 March 1995, Stephen Tweedie
 * Added /proc support, Dec 1995
 * Added /proc support, Dec 1995
 * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
 * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
 * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
 * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
 * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
 * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
 */
 */
 
 
/*
/*
 * uClinux revisions for NO_MM
 * uClinux revisions for NO_MM
 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
 *                     The Silver Hammer Group, Ltd.
 *                     The Silver Hammer Group, Ltd.
 */
 */
 
 
#include <linux/config.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/sysctl.h>
#include <linux/swapctl.h>
#include <linux/swapctl.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/malloc.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/ctype.h>
#include <linux/ctype.h>
#include <asm/bitops.h>
#include <asm/bitops.h>
#include <asm/segment.h>
#include <asm/segment.h>
 
 
#include <linux/utsname.h>
#include <linux/utsname.h>
#include <linux/swapctl.h>
#include <linux/swapctl.h>
 
 
/* External variables not in a header file. */
/* External variables not in a header file. */
extern int panic_timeout;
extern int panic_timeout;
 
 
 
 
#ifdef CONFIG_ROOT_NFS
#ifdef CONFIG_ROOT_NFS
#include <linux/nfs_fs.h>
#include <linux/nfs_fs.h>
#endif
#endif
 
 
static ctl_table root_table[];
static ctl_table root_table[];
static struct ctl_table_header root_table_header =
static struct ctl_table_header root_table_header =
        {root_table, DNODE_SINGLE(&root_table_header)};
        {root_table, DNODE_SINGLE(&root_table_header)};
 
 
static int parse_table(int *, int, void *, size_t *, void *, size_t,
static int parse_table(int *, int, void *, size_t *, void *, size_t,
                       ctl_table *, void **);
                       ctl_table *, void **);
 
 
static ctl_table kern_table[];
static ctl_table kern_table[];
static ctl_table vm_table[];
static ctl_table vm_table[];
extern ctl_table net_table[];
extern ctl_table net_table[];
 
 
/* /proc declarations: */
/* /proc declarations: */
 
 
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
 
 
static int proc_readsys(struct inode * inode, struct file * file,
static int proc_readsys(struct inode * inode, struct file * file,
                        char * buf, int count);
                        char * buf, int count);
static int proc_writesys(struct inode * inode, struct file * file,
static int proc_writesys(struct inode * inode, struct file * file,
                         const char * buf, int count);
                         const char * buf, int count);
static int proc_sys_permission(struct inode *, int);
static int proc_sys_permission(struct inode *, int);
 
 
struct file_operations proc_sys_file_operations =
struct file_operations proc_sys_file_operations =
{
{
        NULL,           /* lseek   */
        NULL,           /* lseek   */
        proc_readsys,   /* read    */
        proc_readsys,   /* read    */
        proc_writesys,  /* write   */
        proc_writesys,  /* write   */
        NULL,           /* readdir */
        NULL,           /* readdir */
        NULL,           /* select  */
        NULL,           /* select  */
        NULL,           /* ioctl   */
        NULL,           /* ioctl   */
        NULL,           /* mmap    */
        NULL,           /* mmap    */
        NULL,           /* no special open code    */
        NULL,           /* no special open code    */
        NULL,           /* no special release code */
        NULL,           /* no special release code */
        NULL            /* can't fsync */
        NULL            /* can't fsync */
};
};
 
 
struct inode_operations proc_sys_inode_operations =
struct inode_operations proc_sys_inode_operations =
{
{
        &proc_sys_file_operations,
        &proc_sys_file_operations,
        NULL,           /* create */
        NULL,           /* create */
        NULL,           /* lookup */
        NULL,           /* lookup */
        NULL,           /* link */
        NULL,           /* link */
        NULL,           /* unlink */
        NULL,           /* unlink */
        NULL,           /* symlink */
        NULL,           /* symlink */
        NULL,           /* mkdir */
        NULL,           /* mkdir */
        NULL,           /* rmdir */
        NULL,           /* rmdir */
        NULL,           /* mknod */
        NULL,           /* mknod */
        NULL,           /* rename */
        NULL,           /* rename */
        NULL,           /* readlink */
        NULL,           /* readlink */
        NULL,           /* follow_link */
        NULL,           /* follow_link */
        NULL,           /* readpage */
        NULL,           /* readpage */
        NULL,           /* writepage */
        NULL,           /* writepage */
        NULL,           /* bmap */
        NULL,           /* bmap */
        NULL,           /* truncate */
        NULL,           /* truncate */
        proc_sys_permission
        proc_sys_permission
};
};
 
 
extern struct proc_dir_entry proc_sys_root;
extern struct proc_dir_entry proc_sys_root;
 
 
static void register_proc_table(ctl_table *, struct proc_dir_entry *);
static void register_proc_table(ctl_table *, struct proc_dir_entry *);
static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
#endif
#endif
 
 
extern int bdf_prm[], bdflush_min[], bdflush_max[];
extern int bdf_prm[], bdflush_min[], bdflush_max[];
 
 
static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
                                    void *, size_t, void **);
                                    void *, size_t, void **);
 
 
extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
 
 
/* The default sysctl tables: */
/* The default sysctl tables: */
 
 
static ctl_table root_table[] = {
static ctl_table root_table[] = {
        {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
        {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
        {CTL_VM, "vm", NULL, 0, 0555, vm_table},
        {CTL_VM, "vm", NULL, 0, 0555, vm_table},
        {CTL_NET, "net", NULL, 0, 0555, net_table},
        {CTL_NET, "net", NULL, 0, 0555, net_table},
        {0}
        {0}
};
};
 
 
static ctl_table kern_table[] = {
static ctl_table kern_table[] = {
        {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
        {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
         0444, NULL, &proc_dostring, &sysctl_string},
         0444, NULL, &proc_dostring, &sysctl_string},
        {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
        {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
         0444, NULL, &proc_dostring, &sysctl_string},
         0444, NULL, &proc_dostring, &sysctl_string},
        {KERN_VERSION, "version", system_utsname.version, 64,
        {KERN_VERSION, "version", system_utsname.version, 64,
         0444, NULL, &proc_dostring, &sysctl_string},
         0444, NULL, &proc_dostring, &sysctl_string},
        {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
        {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
         0644, NULL, &proc_dostring, &sysctl_string},
         0644, NULL, &proc_dostring, &sysctl_string},
        {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
        {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
         0644, NULL, &proc_dostring, &sysctl_string},
         0644, NULL, &proc_dostring, &sysctl_string},
        {KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
        {KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
         0444, NULL, &proc_dointvec},
         0444, NULL, &proc_dointvec},
        {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
        {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
         0644, NULL, &proc_dointvec},
         0644, NULL, &proc_dointvec},
        {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
        {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
         0444, NULL, &proc_dointvec},
         0444, NULL, &proc_dointvec},
        {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
        {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
         0644, NULL, &proc_dointvec},
         0644, NULL, &proc_dointvec},
        {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
        {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
         0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
         0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
        {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
        {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
         0644, NULL, &proc_dointvec},
         0644, NULL, &proc_dointvec},
#ifdef CONFIG_BLK_DEV_INITRD
#ifdef CONFIG_BLK_DEV_INITRD
        {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
        {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
         0644, NULL, &proc_dointvec},
         0644, NULL, &proc_dointvec},
#endif
#endif
#ifdef CONFIG_ROOT_NFS
#ifdef CONFIG_ROOT_NFS
        {KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
        {KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
         0644, NULL, &proc_dostring, &sysctl_string },
         0644, NULL, &proc_dostring, &sysctl_string },
        {KERN_NFSRADDRS, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
        {KERN_NFSRADDRS, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
         0644, NULL, &proc_dostring, &sysctl_string },
         0644, NULL, &proc_dostring, &sysctl_string },
#endif
#endif
#ifdef CONFIG_BINFMT_JAVA
#ifdef CONFIG_BINFMT_JAVA
        {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
        {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
         64, 0644, NULL, &proc_dostring, &sysctl_string },
         64, 0644, NULL, &proc_dostring, &sysctl_string },
        {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
        {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
         64, 0644, NULL, &proc_dostring, &sysctl_string },
         64, 0644, NULL, &proc_dostring, &sysctl_string },
#endif
#endif
        {0}
        {0}
};
};
 
 
static ctl_table vm_table[] = {
static ctl_table vm_table[] = {
#ifndef NO_MM
#ifndef NO_MM
        {VM_SWAPCTL, "swapctl",
        {VM_SWAPCTL, "swapctl",
         &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
         &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
        {VM_KSWAPD, "kswapd",
        {VM_KSWAPD, "kswapd",
         &kswapd_ctl, sizeof(kswapd_ctl), 0600, NULL, &proc_dointvec},
         &kswapd_ctl, sizeof(kswapd_ctl), 0600, NULL, &proc_dointvec},
        {VM_FREEPG, "freepages",
        {VM_FREEPG, "freepages",
         &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
         &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
        {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
        {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
         &proc_dointvec_minmax, &sysctl_intvec, NULL,
         &proc_dointvec_minmax, &sysctl_intvec, NULL,
         &bdflush_min, &bdflush_max},
         &bdflush_min, &bdflush_max},
#endif /* !NO_MM */
#endif /* !NO_MM */
        {0}
        {0}
};
};
 
 
void sysctl_init(void)
void sysctl_init(void)
{
{
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
        register_proc_table(root_table, &proc_sys_root);
        register_proc_table(root_table, &proc_sys_root);
#endif
#endif
}
}
 
 
 
 
int do_sysctl (int *name, int nlen,
int do_sysctl (int *name, int nlen,
               void *oldval, size_t *oldlenp,
               void *oldval, size_t *oldlenp,
               void *newval, size_t newlen)
               void *newval, size_t newlen)
{
{
        int error;
        int error;
        struct ctl_table_header *tmp;
        struct ctl_table_header *tmp;
        void *context;
        void *context;
 
 
        if (nlen <= 0 || nlen >= CTL_MAXNAME)
        if (nlen <= 0 || nlen >= CTL_MAXNAME)
                return -ENOTDIR;
                return -ENOTDIR;
 
 
        error = verify_area(VERIFY_READ,name,nlen*sizeof(int));
        error = verify_area(VERIFY_READ,name,nlen*sizeof(int));
        if (error) return error;
        if (error) return error;
        if (oldval) {
        if (oldval) {
                if (!oldlenp)
                if (!oldlenp)
                        return -EFAULT;
                        return -EFAULT;
                error = verify_area(VERIFY_WRITE,oldlenp,sizeof(size_t));
                error = verify_area(VERIFY_WRITE,oldlenp,sizeof(size_t));
                if (error) return error;
                if (error) return error;
                error = verify_area(VERIFY_WRITE,oldval,get_user(oldlenp));
                error = verify_area(VERIFY_WRITE,oldval,get_user(oldlenp));
                if (error) return error;
                if (error) return error;
        }
        }
        if (newval) {
        if (newval) {
                error = verify_area(VERIFY_READ,newval,newlen);
                error = verify_area(VERIFY_READ,newval,newlen);
                if (error) return error;
                if (error) return error;
        }
        }
        tmp = &root_table_header;
        tmp = &root_table_header;
        do {
        do {
                context = 0;
                context = 0;
                error = parse_table(name, nlen, oldval, oldlenp,
                error = parse_table(name, nlen, oldval, oldlenp,
                                    newval, newlen, tmp->ctl_table, &context);
                                    newval, newlen, tmp->ctl_table, &context);
                if (context)
                if (context)
                        kfree(context);
                        kfree(context);
                if (error != -ENOTDIR)
                if (error != -ENOTDIR)
                        return error;
                        return error;
                tmp = tmp->DLIST_NEXT(ctl_entry);
                tmp = tmp->DLIST_NEXT(ctl_entry);
        } while (tmp != &root_table_header);
        } while (tmp != &root_table_header);
        return -ENOTDIR;
        return -ENOTDIR;
}
}
 
 
extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
{
{
        struct __sysctl_args tmp;
        struct __sysctl_args tmp;
        int error;
        int error;
        error = verify_area(VERIFY_READ, args, sizeof(*args));
        error = verify_area(VERIFY_READ, args, sizeof(*args));
        if (error)
        if (error)
                return error;
                return error;
        memcpy_fromfs(&tmp, args, sizeof(tmp));
        memcpy_fromfs(&tmp, args, sizeof(tmp));
        return do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
        return do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
                         tmp.newval, tmp.newlen);
                         tmp.newval, tmp.newlen);
}
}
 
 
/* Like in_group_p, but testing against egid, not fsgid */
/* Like in_group_p, but testing against egid, not fsgid */
static int in_egroup_p(gid_t grp)
static int in_egroup_p(gid_t grp)
{
{
        int     i;
        int     i;
 
 
        if (grp == current->egid)
        if (grp == current->egid)
                return 1;
                return 1;
 
 
        for (i = 0; i < NGROUPS; i++) {
        for (i = 0; i < NGROUPS; i++) {
                if (current->groups[i] == NOGROUP)
                if (current->groups[i] == NOGROUP)
                        break;
                        break;
                if (current->groups[i] == grp)
                if (current->groups[i] == grp)
                        return 1;
                        return 1;
        }
        }
        return 0;
        return 0;
}
}
/* ctl_perm does NOT grant the superuser all rights automatically, because
/* ctl_perm does NOT grant the superuser all rights automatically, because
   some sysctl variables are readonly even to root. */
   some sysctl variables are readonly even to root. */
static int test_perm(int mode, int op)
static int test_perm(int mode, int op)
{
{
        if (!current->euid)
        if (!current->euid)
                mode >>= 6;
                mode >>= 6;
        else if (in_egroup_p(0))
        else if (in_egroup_p(0))
                mode >>= 3;
                mode >>= 3;
        if ((mode & op & 0007) == op)
        if ((mode & op & 0007) == op)
                return 0;
                return 0;
        return -EACCES;
        return -EACCES;
}
}
static inline int ctl_perm(ctl_table *table, int op)
static inline int ctl_perm(ctl_table *table, int op)
{
{
        return test_perm(table->mode, op);
        return test_perm(table->mode, op);
}
}
 
 
static int parse_table(int *name, int nlen,
static int parse_table(int *name, int nlen,
                       void *oldval, size_t *oldlenp,
                       void *oldval, size_t *oldlenp,
                       void *newval, size_t newlen,
                       void *newval, size_t newlen,
                       ctl_table *table, void **context)
                       ctl_table *table, void **context)
{
{
        int error;
        int error;
repeat:
repeat:
        if (!nlen)
        if (!nlen)
                return -ENOTDIR;
                return -ENOTDIR;
 
 
        for ( ; table->ctl_name; table++) {
        for ( ; table->ctl_name; table++) {
                if (get_user(name) == table->ctl_name ||
                if (get_user(name) == table->ctl_name ||
                    table->ctl_name == CTL_ANY) {
                    table->ctl_name == CTL_ANY) {
                        if (table->child) {
                        if (table->child) {
                                if (ctl_perm(table, 001))
                                if (ctl_perm(table, 001))
                                        return -EPERM;
                                        return -EPERM;
                                if (table->strategy) {
                                if (table->strategy) {
                                        error = table->strategy(
                                        error = table->strategy(
                                                table, name, nlen,
                                                table, name, nlen,
                                                oldval, oldlenp,
                                                oldval, oldlenp,
                                                newval, newlen, context);
                                                newval, newlen, context);
                                if (error)
                                if (error)
                                        return error;
                                        return error;
                                }
                                }
                                name++;
                                name++;
                                nlen--;
                                nlen--;
                                table = table->child;
                                table = table->child;
                                goto repeat;
                                goto repeat;
                        }
                        }
                        error = do_sysctl_strategy(table, name, nlen,
                        error = do_sysctl_strategy(table, name, nlen,
                                                   oldval, oldlenp,
                                                   oldval, oldlenp,
                                                   newval, newlen, context);
                                                   newval, newlen, context);
                        return error;
                        return error;
                }
                }
        };
        };
        return -ENOTDIR;
        return -ENOTDIR;
}
}
 
 
/* Perform the actual read/write of a sysctl table entry. */
/* Perform the actual read/write of a sysctl table entry. */
int do_sysctl_strategy (ctl_table *table,
int do_sysctl_strategy (ctl_table *table,
                        int *name, int nlen,
                        int *name, int nlen,
                        void *oldval, size_t *oldlenp,
                        void *oldval, size_t *oldlenp,
                        void *newval, size_t newlen, void **context)
                        void *newval, size_t newlen, void **context)
{
{
        int op = 0, rc, len;
        int op = 0, rc, len;
 
 
        if (oldval)
        if (oldval)
                op |= 004;
                op |= 004;
        if (newval)
        if (newval)
                op |= 002;
                op |= 002;
        if (ctl_perm(table, op))
        if (ctl_perm(table, op))
                if( table->data != &securelevel || current->euid)
                if( table->data != &securelevel || current->euid)
                        return -EPERM;
                        return -EPERM;
 
 
        if (table->strategy) {
        if (table->strategy) {
                rc = table->strategy(table, name, nlen, oldval, oldlenp,
                rc = table->strategy(table, name, nlen, oldval, oldlenp,
                                     newval, newlen, context);
                                     newval, newlen, context);
                if (rc < 0)
                if (rc < 0)
                        return rc;
                        return rc;
                if (rc > 0)
                if (rc > 0)
                        return 0;
                        return 0;
        }
        }
 
 
        /* If there is no strategy routine, or if the strategy returns
        /* If there is no strategy routine, or if the strategy returns
         * zero, proceed with automatic r/w */
         * zero, proceed with automatic r/w */
        if (table->data && table->maxlen) {
        if (table->data && table->maxlen) {
                if (oldval && oldlenp && get_user(oldlenp)) {
                if (oldval && oldlenp && get_user(oldlenp)) {
                        len = get_user(oldlenp);
                        len = get_user(oldlenp);
                        if (len > table->maxlen)
                        if (len > table->maxlen)
                                len = table->maxlen;
                                len = table->maxlen;
                        memcpy_tofs(oldval, table->data, len);
                        memcpy_tofs(oldval, table->data, len);
                        put_user(len, oldlenp);
                        put_user(len, oldlenp);
                }
                }
                if (newval && newlen) {
                if (newval && newlen) {
                        len = newlen;
                        len = newlen;
                        if (len > table->maxlen)
                        if (len > table->maxlen)
                                len = table->maxlen;
                                len = table->maxlen;
                        memcpy_fromfs(table->data, newval, len);
                        memcpy_fromfs(table->data, newval, len);
                }
                }
        }
        }
        return 0;
        return 0;
}
}
 
 
/*
/*
 * This function only checks permission for changing the security level
 * This function only checks permission for changing the security level
 * If the tests are successful, the actual change is done by
 * If the tests are successful, the actual change is done by
 * do_sysctl_strategy
 * do_sysctl_strategy
 */
 */
static int do_securelevel_strategy (ctl_table *table,
static int do_securelevel_strategy (ctl_table *table,
                                    int *name, int nlen,
                                    int *name, int nlen,
                                    void *oldval, size_t *oldlenp,
                                    void *oldval, size_t *oldlenp,
                                    void *newval, size_t newlen, void **context)
                                    void *newval, size_t newlen, void **context)
{
{
        int level;
        int level;
 
 
        if (newval && newlen) {
        if (newval && newlen) {
                if (newlen != sizeof (int))
                if (newlen != sizeof (int))
                        return -EINVAL;
                        return -EINVAL;
                memcpy_fromfs (&level, newval, newlen);
                memcpy_fromfs (&level, newval, newlen);
                if (level < securelevel && current->pid != 1)
                if (level < securelevel && current->pid != 1)
                        return -EPERM;
                        return -EPERM;
        }
        }
        return 0;
        return 0;
}
}
 
 
struct ctl_table_header *register_sysctl_table(ctl_table * table,
struct ctl_table_header *register_sysctl_table(ctl_table * table,
                                               int insert_at_head)
                                               int insert_at_head)
{
{
        struct ctl_table_header *tmp;
        struct ctl_table_header *tmp;
        tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
        tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
        if (!tmp)
        if (!tmp)
                return 0;
                return 0;
        *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
        *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
        if (insert_at_head)
        if (insert_at_head)
                DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
                DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
        else
        else
                DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
                DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
        register_proc_table(table, &proc_sys_root);
        register_proc_table(table, &proc_sys_root);
#endif
#endif
        return tmp;
        return tmp;
}
}
 
 
void unregister_sysctl_table(struct ctl_table_header * header)
void unregister_sysctl_table(struct ctl_table_header * header)
{
{
        DLIST_DELETE(header, ctl_entry);
        DLIST_DELETE(header, ctl_entry);
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
        unregister_proc_table(header->ctl_table, &proc_sys_root);
        unregister_proc_table(header->ctl_table, &proc_sys_root);
#endif
#endif
        kfree(header);
        kfree(header);
}
}
 
 
/*
/*
 * /proc/sys support
 * /proc/sys support
 */
 */
 
 
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
 
 
/* Scan the sysctl entries in table and add them all into /proc */
/* Scan the sysctl entries in table and add them all into /proc */
static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
{
{
        struct proc_dir_entry *de, *tmp;
        struct proc_dir_entry *de, *tmp;
        int exists;
        int exists;
 
 
        for (; table->ctl_name; table++) {
        for (; table->ctl_name; table++) {
                exists = 0;
                exists = 0;
                /* Can't do anything without a proc name. */
                /* Can't do anything without a proc name. */
                if (!table->procname)
                if (!table->procname)
                        continue;
                        continue;
                /* Maybe we can't do anything with it... */
                /* Maybe we can't do anything with it... */
                if (!table->proc_handler &&
                if (!table->proc_handler &&
                    !table->child)
                    !table->child)
                        continue;
                        continue;
 
 
                de = kmalloc(sizeof(*de), GFP_KERNEL);
                de = kmalloc(sizeof(*de), GFP_KERNEL);
                if (!de) continue;
                if (!de) continue;
                de->namelen = strlen(table->procname);
                de->namelen = strlen(table->procname);
                de->name = table->procname;
                de->name = table->procname;
                de->mode = table->mode;
                de->mode = table->mode;
                de->nlink = 1;
                de->nlink = 1;
                de->uid = 0;
                de->uid = 0;
                de->gid = 0;
                de->gid = 0;
                de->size = 0;
                de->size = 0;
                de->get_info = 0;        /* For internal use if we want it */
                de->get_info = 0;        /* For internal use if we want it */
                de->fill_inode = 0;      /* To override struct inode fields */
                de->fill_inode = 0;      /* To override struct inode fields */
                de->next = de->subdir = 0;
                de->next = de->subdir = 0;
                de->data = (void *) table;
                de->data = (void *) table;
                /* Is it a file? */
                /* Is it a file? */
                if (table->proc_handler) {
                if (table->proc_handler) {
                        de->ops = &proc_sys_inode_operations;
                        de->ops = &proc_sys_inode_operations;
                        de->mode |= S_IFREG;
                        de->mode |= S_IFREG;
                }
                }
                /* Otherwise it's a subdir */
                /* Otherwise it's a subdir */
                else  {
                else  {
                        /* First check to see if it already exists */
                        /* First check to see if it already exists */
                        for (tmp = root->subdir; tmp; tmp = tmp->next) {
                        for (tmp = root->subdir; tmp; tmp = tmp->next) {
                                if (tmp->namelen == de->namelen &&
                                if (tmp->namelen == de->namelen &&
                                    !memcmp(tmp->name,de->name,de->namelen)) {
                                    !memcmp(tmp->name,de->name,de->namelen)) {
                                        exists = 1;
                                        exists = 1;
                                        kfree (de);
                                        kfree (de);
                                        de = tmp;
                                        de = tmp;
                                }
                                }
                        }
                        }
                        if (!exists) {
                        if (!exists) {
                                de->ops = &proc_dir_inode_operations;
                                de->ops = &proc_dir_inode_operations;
                                de->nlink++;
                                de->nlink++;
                                de->mode |= S_IFDIR;
                                de->mode |= S_IFDIR;
                        }
                        }
                }
                }
                table->de = de;
                table->de = de;
                if (!exists)
                if (!exists)
                        proc_register_dynamic(root, de);
                        proc_register_dynamic(root, de);
                if (de->mode & S_IFDIR )
                if (de->mode & S_IFDIR )
                        register_proc_table(table->child, de);
                        register_proc_table(table->child, de);
        }
        }
}
}
 
 
static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
{
{
        struct proc_dir_entry *de;
        struct proc_dir_entry *de;
        for (; table->ctl_name; table++) {
        for (; table->ctl_name; table++) {
                if (!(de = table->de))
                if (!(de = table->de))
                        continue;
                        continue;
                if (de->mode & S_IFDIR) {
                if (de->mode & S_IFDIR) {
                        if (!table->child) {
                        if (!table->child) {
                                printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
                                printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
                                continue;
                                continue;
                        }
                        }
                        unregister_proc_table(table->child, de);
                        unregister_proc_table(table->child, de);
                }
                }
                /* Don't unregister proc directories which still have
                /* Don't unregister proc directories which still have
                   entries... */
                   entries... */
                if (!((de->mode & S_IFDIR) && de->subdir)) {
                if (!((de->mode & S_IFDIR) && de->subdir)) {
                        proc_unregister(root, de->low_ino);
                        proc_unregister(root, de->low_ino);
                        table->de = NULL;
                        table->de = NULL;
                        kfree(de);
                        kfree(de);
                }
                }
        }
        }
}
}
 
 
 
 
static int do_rw_proc(int write, struct inode * inode, struct file * file,
static int do_rw_proc(int write, struct inode * inode, struct file * file,
                      char * buf, int count)
                      char * buf, int count)
{
{
        int error, op;
        int error, op;
        struct proc_dir_entry *de;
        struct proc_dir_entry *de;
        struct ctl_table *table;
        struct ctl_table *table;
        size_t res;
        size_t res;
 
 
        error = verify_area(write ? VERIFY_READ : VERIFY_WRITE, buf, count);
        error = verify_area(write ? VERIFY_READ : VERIFY_WRITE, buf, count);
        if (error)
        if (error)
                return error;
                return error;
 
 
        de = (struct proc_dir_entry*) inode->u.generic_ip;
        de = (struct proc_dir_entry*) inode->u.generic_ip;
        if (!de || !de->data)
        if (!de || !de->data)
                return -ENOTDIR;
                return -ENOTDIR;
        table = (struct ctl_table *) de->data;
        table = (struct ctl_table *) de->data;
        if (!table || !table->proc_handler)
        if (!table || !table->proc_handler)
                return -ENOTDIR;
                return -ENOTDIR;
        op = (write ? 002 : 004);
        op = (write ? 002 : 004);
        if (ctl_perm(table, op))
        if (ctl_perm(table, op))
                return -EPERM;
                return -EPERM;
 
 
        res = count;
        res = count;
        error = (*table->proc_handler) (table, write, file, buf, &res);
        error = (*table->proc_handler) (table, write, file, buf, &res);
        if (error)
        if (error)
                return error;
                return error;
        return res;
        return res;
}
}
 
 
static int proc_readsys(struct inode * inode, struct file * file,
static int proc_readsys(struct inode * inode, struct file * file,
                        char * buf, int count)
                        char * buf, int count)
{
{
        return do_rw_proc(0, inode, file, buf, count);
        return do_rw_proc(0, inode, file, buf, count);
}
}
 
 
static int proc_writesys(struct inode * inode, struct file * file,
static int proc_writesys(struct inode * inode, struct file * file,
                         const char * buf, int count)
                         const char * buf, int count)
{
{
        return do_rw_proc(1, inode, file, (char *) buf, count);
        return do_rw_proc(1, inode, file, (char *) buf, count);
}
}
 
 
static int proc_sys_permission(struct inode *inode, int op)
static int proc_sys_permission(struct inode *inode, int op)
{
{
        return test_perm(inode->i_mode, op);
        return test_perm(inode->i_mode, op);
}
}
 
 
int proc_dostring(ctl_table *table, int write, struct file *filp,
int proc_dostring(ctl_table *table, int write, struct file *filp,
                  void *buffer, size_t *lenp)
                  void *buffer, size_t *lenp)
{
{
        int len;
        int len;
        char *p, c;
        char *p, c;
 
 
        if (!table->data || !table->maxlen || !*lenp ||
        if (!table->data || !table->maxlen || !*lenp ||
            (filp->f_pos && !write)) {
            (filp->f_pos && !write)) {
                *lenp = 0;
                *lenp = 0;
                return 0;
                return 0;
        }
        }
 
 
        if (write) {
        if (write) {
                len = 0;
                len = 0;
                p = buffer;
                p = buffer;
                while (len < *lenp &&
                while (len < *lenp &&
                       (c = get_user(p++)) != 0 && c != '\n')
                       (c = get_user(p++)) != 0 && c != '\n')
                        len++;
                        len++;
                if (len >= table->maxlen)
                if (len >= table->maxlen)
                        len = table->maxlen-1;
                        len = table->maxlen-1;
                memcpy_fromfs(table->data, buffer, len);
                memcpy_fromfs(table->data, buffer, len);
                ((char *) table->data)[len] = 0;
                ((char *) table->data)[len] = 0;
                filp->f_pos += *lenp;
                filp->f_pos += *lenp;
        } else {
        } else {
                len = strlen(table->data);
                len = strlen(table->data);
                if (len > table->maxlen)
                if (len > table->maxlen)
                        len = table->maxlen;
                        len = table->maxlen;
                if (len > *lenp)
                if (len > *lenp)
                        len = *lenp;
                        len = *lenp;
                if (len)
                if (len)
                        memcpy_tofs(buffer, table->data, len);
                        memcpy_tofs(buffer, table->data, len);
                if (len < *lenp) {
                if (len < *lenp) {
                        put_user('\n', ((char *) buffer) + len);
                        put_user('\n', ((char *) buffer) + len);
                        len++;
                        len++;
                }
                }
                *lenp = len;
                *lenp = len;
                filp->f_pos += len;
                filp->f_pos += len;
        }
        }
        return 0;
        return 0;
}
}
 
 
int proc_dointvec(ctl_table *table, int write, struct file *filp,
int proc_dointvec(ctl_table *table, int write, struct file *filp,
                  void *buffer, size_t *lenp)
                  void *buffer, size_t *lenp)
{
{
        int *i, vleft, first=1, len, left, neg, val;
        int *i, vleft, first=1, len, left, neg, val;
        #define TMPBUFLEN 20
        #define TMPBUFLEN 20
        char buf[TMPBUFLEN], *p;
        char buf[TMPBUFLEN], *p;
 
 
        if (!table->data || !table->maxlen || !*lenp ||
        if (!table->data || !table->maxlen || !*lenp ||
            (filp->f_pos && !write)) {
            (filp->f_pos && !write)) {
                *lenp = 0;
                *lenp = 0;
                return 0;
                return 0;
        }
        }
 
 
        i = (int *) table->data;
        i = (int *) table->data;
        vleft = table->maxlen / sizeof(int);
        vleft = table->maxlen / sizeof(int);
        left = *lenp;
        left = *lenp;
 
 
        for (; left && vleft--; i++, first=0) {
        for (; left && vleft--; i++, first=0) {
                if (write) {
                if (write) {
                        while (left && isspace(get_user((char *) buffer)))
                        while (left && isspace(get_user((char *) buffer)))
                                left--, ((char *) buffer)++;
                                left--, ((char *) buffer)++;
                        if (!left)
                        if (!left)
                                break;
                                break;
                        neg = 0;
                        neg = 0;
                        len = left;
                        len = left;
                        if (len > TMPBUFLEN-1)
                        if (len > TMPBUFLEN-1)
                                len = TMPBUFLEN-1;
                                len = TMPBUFLEN-1;
                        memcpy_fromfs(buf, buffer, len);
                        memcpy_fromfs(buf, buffer, len);
                        buf[len] = 0;
                        buf[len] = 0;
                        p = buf;
                        p = buf;
                        if (*p == '-' && left > 1) {
                        if (*p == '-' && left > 1) {
                                neg = 1;
                                neg = 1;
                                left--, p++;
                                left--, p++;
                        }
                        }
                        if (*p < '0' || *p > '9')
                        if (*p < '0' || *p > '9')
                                break;
                                break;
                        val = simple_strtoul(p, &p, 0);
                        val = simple_strtoul(p, &p, 0);
                        len = p-buf;
                        len = p-buf;
                        if ((len < left) && *p && !isspace(*p))
                        if ((len < left) && *p && !isspace(*p))
                                break;
                                break;
                        if (neg)
                        if (neg)
                                val = -val;
                                val = -val;
                        buffer += len;
                        buffer += len;
                        left -= len;
                        left -= len;
                        *i = val;
                        *i = val;
                } else {
                } else {
                        p = buf;
                        p = buf;
                        if (!first)
                        if (!first)
                                *p++ = '\t';
                                *p++ = '\t';
                        sprintf(p, "%d", *i);
                        sprintf(p, "%d", *i);
                        len = strlen(buf);
                        len = strlen(buf);
                        if (len > left)
                        if (len > left)
                                len = left;
                                len = left;
                        memcpy_tofs(buffer, buf, len);
                        memcpy_tofs(buffer, buf, len);
                        left -= len;
                        left -= len;
                        buffer += len;
                        buffer += len;
                }
                }
        }
        }
 
 
        if (!write && !first && left) {
        if (!write && !first && left) {
                put_user('\n', (char *) buffer);
                put_user('\n', (char *) buffer);
                left--, buffer++;
                left--, buffer++;
        }
        }
        if (write) {
        if (write) {
                p = (char *) buffer;
                p = (char *) buffer;
                while (left && isspace(get_user(p++)))
                while (left && isspace(get_user(p++)))
                        left--;
                        left--;
        }
        }
        if (write && first)
        if (write && first)
                return -EINVAL;
                return -EINVAL;
        *lenp -= left;
        *lenp -= left;
        filp->f_pos += *lenp;
        filp->f_pos += *lenp;
        return 0;
        return 0;
}
}
 
 
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
                  void *buffer, size_t *lenp)
                  void *buffer, size_t *lenp)
{
{
        int *i, *min, *max, vleft, first=1, len, left, neg, val;
        int *i, *min, *max, vleft, first=1, len, left, neg, val;
        #define TMPBUFLEN 20
        #define TMPBUFLEN 20
        char buf[TMPBUFLEN], *p;
        char buf[TMPBUFLEN], *p;
 
 
        if (!table->data || !table->maxlen || !*lenp ||
        if (!table->data || !table->maxlen || !*lenp ||
            (filp->f_pos && !write)) {
            (filp->f_pos && !write)) {
                *lenp = 0;
                *lenp = 0;
                return 0;
                return 0;
        }
        }
 
 
        i = (int *) table->data;
        i = (int *) table->data;
        min = (int *) table->extra1;
        min = (int *) table->extra1;
        max = (int *) table->extra2;
        max = (int *) table->extra2;
        vleft = table->maxlen / sizeof(int);
        vleft = table->maxlen / sizeof(int);
        left = *lenp;
        left = *lenp;
 
 
        for (; left && vleft--; i++, first=0) {
        for (; left && vleft--; i++, first=0) {
                if (write) {
                if (write) {
                        while (left && isspace(get_user((char *) buffer)))
                        while (left && isspace(get_user((char *) buffer)))
                                left--, ((char *) buffer)++;
                                left--, ((char *) buffer)++;
                        if (!left)
                        if (!left)
                                break;
                                break;
                        neg = 0;
                        neg = 0;
                        len = left;
                        len = left;
                        if (len > TMPBUFLEN-1)
                        if (len > TMPBUFLEN-1)
                                len = TMPBUFLEN-1;
                                len = TMPBUFLEN-1;
                        memcpy_fromfs(buf, buffer, len);
                        memcpy_fromfs(buf, buffer, len);
                        buf[len] = 0;
                        buf[len] = 0;
                        p = buf;
                        p = buf;
                        if (*p == '-' && left > 1) {
                        if (*p == '-' && left > 1) {
                                neg = 1;
                                neg = 1;
                                left--, p++;
                                left--, p++;
                        }
                        }
                        if (*p < '0' || *p > '9')
                        if (*p < '0' || *p > '9')
                                break;
                                break;
                        val = simple_strtoul(p, &p, 0);
                        val = simple_strtoul(p, &p, 0);
                        len = p-buf;
                        len = p-buf;
                        if ((len < left) && *p && !isspace(*p))
                        if ((len < left) && *p && !isspace(*p))
                                break;
                                break;
                        if (neg)
                        if (neg)
                                val = -val;
                                val = -val;
                        buffer += len;
                        buffer += len;
                        left -= len;
                        left -= len;
 
 
                        if (min && val < *min++)
                        if (min && val < *min++)
                                continue;
                                continue;
                        if (max && val > *max++)
                        if (max && val > *max++)
                                continue;
                                continue;
                        *i = val;
                        *i = val;
                } else {
                } else {
                        p = buf;
                        p = buf;
                        if (!first)
                        if (!first)
                                *p++ = '\t';
                                *p++ = '\t';
                        sprintf(p, "%d", *i);
                        sprintf(p, "%d", *i);
                        len = strlen(buf);
                        len = strlen(buf);
                        if (len > left)
                        if (len > left)
                                len = left;
                                len = left;
                        memcpy_tofs(buffer, buf, len);
                        memcpy_tofs(buffer, buf, len);
                        left -= len;
                        left -= len;
                        buffer += len;
                        buffer += len;
                }
                }
        }
        }
 
 
        if (!write && !first && left) {
        if (!write && !first && left) {
                put_user('\n', (char *) buffer);
                put_user('\n', (char *) buffer);
                left--, buffer++;
                left--, buffer++;
        }
        }
        if (write) {
        if (write) {
                p = (char *) buffer;
                p = (char *) buffer;
                while (left && isspace(get_user(p++)))
                while (left && isspace(get_user(p++)))
                        left--;
                        left--;
        }
        }
        if (write && first)
        if (write && first)
                return -EINVAL;
                return -EINVAL;
        *lenp -= left;
        *lenp -= left;
        filp->f_pos += *lenp;
        filp->f_pos += *lenp;
        return 0;
        return 0;
}
}
 
 
#else /* CONFIG_PROC_FS */
#else /* CONFIG_PROC_FS */
 
 
int proc_dostring(ctl_table *table, int write, struct file *filp,
int proc_dostring(ctl_table *table, int write, struct file *filp,
                  void *buffer, size_t *lenp)
                  void *buffer, size_t *lenp)
{
{
        return -ENOSYS;
        return -ENOSYS;
}
}
 
 
int proc_dointvec(ctl_table *table, int write, struct file *filp,
int proc_dointvec(ctl_table *table, int write, struct file *filp,
                  void *buffer, size_t *lenp)
                  void *buffer, size_t *lenp)
{
{
        return -ENOSYS;
        return -ENOSYS;
}
}
 
 
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
                    void *buffer, size_t *lenp)
                    void *buffer, size_t *lenp)
{
{
        return -ENOSYS;
        return -ENOSYS;
}
}
 
 
#endif /* CONFIG_PROC_FS */
#endif /* CONFIG_PROC_FS */
 
 
 
 
/*
/*
 * General sysctl support routines
 * General sysctl support routines
 */
 */
 
 
/* The generic string strategy routine: */
/* The generic string strategy routine: */
int sysctl_string(ctl_table *table, int *name, int nlen,
int sysctl_string(ctl_table *table, int *name, int nlen,
                  void *oldval, size_t *oldlenp,
                  void *oldval, size_t *oldlenp,
                  void *newval, size_t newlen, void **context)
                  void *newval, size_t newlen, void **context)
{
{
        int l, len;
        int l, len;
 
 
        if (!table->data || !table->maxlen)
        if (!table->data || !table->maxlen)
                return -ENOTDIR;
                return -ENOTDIR;
 
 
        if (oldval && oldlenp && get_user(oldlenp)) {
        if (oldval && oldlenp && get_user(oldlenp)) {
                len = get_user(oldlenp);
                len = get_user(oldlenp);
                l = strlen(table->data);
                l = strlen(table->data);
                if (len > l) len = l;
                if (len > l) len = l;
                if (len >= table->maxlen)
                if (len >= table->maxlen)
                        len = table->maxlen;
                        len = table->maxlen;
                memcpy_tofs(oldval, table->data, len);
                memcpy_tofs(oldval, table->data, len);
                put_user(0, ((char *) oldval) + len);
                put_user(0, ((char *) oldval) + len);
                put_user(len, oldlenp);
                put_user(len, oldlenp);
        }
        }
        if (newval && newlen) {
        if (newval && newlen) {
                len = newlen;
                len = newlen;
                if (len > table->maxlen)
                if (len > table->maxlen)
                        len = table->maxlen;
                        len = table->maxlen;
                memcpy_fromfs(table->data, newval, len);
                memcpy_fromfs(table->data, newval, len);
                if (len == table->maxlen)
                if (len == table->maxlen)
                        len--;
                        len--;
                ((char *) table->data)[len] = 0;
                ((char *) table->data)[len] = 0;
        }
        }
        return 0;
        return 0;
}
}
 
 
/*
/*
 * This function makes sure that all of the integers in the vector
 * This function makes sure that all of the integers in the vector
 * are between the minimum and maximum values given in the arrays
 * are between the minimum and maximum values given in the arrays
 * table->extra1 and table->extra2, respectively.
 * table->extra1 and table->extra2, respectively.
 */
 */
int sysctl_intvec(ctl_table *table, int *name, int nlen,
int sysctl_intvec(ctl_table *table, int *name, int nlen,
                void *oldval, size_t *oldlenp,
                void *oldval, size_t *oldlenp,
                void *newval, size_t newlen, void **context)
                void *newval, size_t newlen, void **context)
{
{
        int i, length, *vec, *min, *max;
        int i, length, *vec, *min, *max;
 
 
        if (newval && newlen) {
        if (newval && newlen) {
                if (newlen % sizeof(int) != 0)
                if (newlen % sizeof(int) != 0)
                        return -EINVAL;
                        return -EINVAL;
 
 
                if (!table->extra1 && !table->extra2)
                if (!table->extra1 && !table->extra2)
                        return 0;
                        return 0;
 
 
                if (newlen > table->maxlen)
                if (newlen > table->maxlen)
                        newlen = table->maxlen;
                        newlen = table->maxlen;
                length = newlen / sizeof(int);
                length = newlen / sizeof(int);
 
 
                vec = (int *) newval;
                vec = (int *) newval;
                min = (int *) table->extra1;
                min = (int *) table->extra1;
                max = (int *) table->extra2;
                max = (int *) table->extra2;
 
 
                for (i = 0; i < length; i++) {
                for (i = 0; i < length; i++) {
                        int value = get_user(vec + i);
                        int value = get_user(vec + i);
                        if (min && value < min[i])
                        if (min && value < min[i])
                                return -EINVAL;
                                return -EINVAL;
                        if (max && value > max[i])
                        if (max && value > max[i])
                                return -EINVAL;
                                return -EINVAL;
                }
                }
        }
        }
        return 0;
        return 0;
}
}
 
 
int do_string (
int do_string (
        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
        int rdwr, char *data, size_t max)
        int rdwr, char *data, size_t max)
{
{
        int l = strlen(data) + 1;
        int l = strlen(data) + 1;
        if (newval && !rdwr)
        if (newval && !rdwr)
                return -EPERM;
                return -EPERM;
        if (newval && newlen >= max)
        if (newval && newlen >= max)
                return -EINVAL;
                return -EINVAL;
        if (oldval) {
        if (oldval) {
                if (l > get_user(oldlenp))
                if (l > get_user(oldlenp))
                        return -ENOMEM;
                        return -ENOMEM;
                put_user(l, oldlenp);
                put_user(l, oldlenp);
                memcpy_tofs(oldval, data, l);
                memcpy_tofs(oldval, data, l);
        }
        }
        if (newval) {
        if (newval) {
                memcpy_fromfs(data, newval, newlen);
                memcpy_fromfs(data, newval, newlen);
                data[newlen] = 0;
                data[newlen] = 0;
        }
        }
        return 0;
        return 0;
}
}
 
 
int do_int (
int do_int (
        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
        int rdwr, int *data)
        int rdwr, int *data)
{
{
        if (newval && !rdwr)
        if (newval && !rdwr)
                return -EPERM;
                return -EPERM;
        if (newval && newlen != sizeof(int))
        if (newval && newlen != sizeof(int))
                return -EINVAL;
                return -EINVAL;
        if (oldval) {
        if (oldval) {
                if (get_user(oldlenp) < sizeof(int))
                if (get_user(oldlenp) < sizeof(int))
                        return -ENOMEM;
                        return -ENOMEM;
                put_user(sizeof(int), oldlenp);
                put_user(sizeof(int), oldlenp);
                memcpy_tofs(oldval, data, sizeof(int));
                memcpy_tofs(oldval, data, sizeof(int));
        }
        }
        if (newval)
        if (newval)
                memcpy_fromfs(data, newval, sizeof(int));
                memcpy_fromfs(data, newval, sizeof(int));
        return 0;
        return 0;
}
}
 
 
int do_struct (
int do_struct (
        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
        void *oldval, size_t *oldlenp, void *newval, size_t newlen,
        int rdwr, void *data, size_t len)
        int rdwr, void *data, size_t len)
{
{
        if (newval && !rdwr)
        if (newval && !rdwr)
                return -EPERM;
                return -EPERM;
        if (newval && newlen != len)
        if (newval && newlen != len)
                return -EINVAL;
                return -EINVAL;
        if (oldval) {
        if (oldval) {
                if (get_user(oldlenp) < len)
                if (get_user(oldlenp) < len)
                        return -ENOMEM;
                        return -ENOMEM;
                put_user(len, oldlenp);
                put_user(len, oldlenp);
                memcpy_tofs(oldval, data, len);
                memcpy_tofs(oldval, data, len);
        }
        }
        if (newval)
        if (newval)
                memcpy_fromfs(data, newval, len);
                memcpy_fromfs(data, newval, len);
        return 0;
        return 0;
}
}
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.