diff options
| author | atatat <atatat@NetBSD.org> | 2003-12-04 19:38:21 +0000 |
|---|---|---|
| committer | atatat <atatat@NetBSD.org> | 2003-12-04 19:38:21 +0000 |
| commit | 13f8d2ce5f694f1d39fd03a6fb33ca9214fb48dd (patch) | |
| tree | f8d176cc4fa9b1a693612e2fcb4ca65973214880 /sys/compat/linux/common/linux_sysctl.c | |
| parent | 4d83fe939f20522718c785f48eb99df34c44feee (diff) | |
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
Diffstat (limited to 'sys/compat/linux/common/linux_sysctl.c')
| -rw-r--r-- | sys/compat/linux/common/linux_sysctl.c | 362 |
1 files changed, 151 insertions, 211 deletions
diff --git a/sys/compat/linux/common/linux_sysctl.c b/sys/compat/linux/common/linux_sysctl.c index c82262c7deb..9f4e7630e3f 100644 --- a/sys/compat/linux/common/linux_sysctl.c +++ b/sys/compat/linux/common/linux_sysctl.c @@ -1,11 +1,11 @@ -/* $NetBSD: linux_sysctl.c,v 1.10 2003/08/07 16:30:45 agc Exp $ */ +/* $NetBSD: linux_sysctl.c,v 1.11 2003/12/04 19:38:23 atatat Exp $ */ /*- - * Copyright (c) 1982, 1986, 1989, 1993 - * The Regents of the University of California. All rights reserved. + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. * - * This code is derived from software contributed to Berkeley by - * Mike Karels at Berkeley Software Design, Inc. + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Brown. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -15,23 +15,25 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)kern_sysctl.c 8.9 (Berkeley) 5/20/95 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ /* @@ -39,7 +41,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux_sysctl.c,v 1.10 2003/08/07 16:30:45 agc Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_sysctl.c,v 1.11 2003/12/04 19:38:23 atatat Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -57,229 +59,167 @@ __KERNEL_RCSID(0, "$NetBSD: linux_sysctl.c,v 1.10 2003/08/07 16:30:45 agc Exp $" #include <compat/linux/common/linux_sysctl.h> #include <compat/linux/common/linux_exec.h> -int linux_kern_sysctl(int *, u_int, void *, size_t *, void *, size_t, - struct proc *); -int linux_vm_sysctl(int *, u_int, void *, size_t *, void *, size_t, - struct proc *); -int linux_net_sysctl(int *, u_int, void *, size_t *, void *, size_t, - struct proc *); -int linux_proc_sysctl(int *, u_int, void *, size_t *, void *, size_t, - struct proc *); -int linux_fs_sysctl(int *, u_int, void *, size_t *, void *, size_t, - struct proc *); -#ifdef DEBUG -int linux_debug_sysctl(int *, u_int, void *, size_t *, void *, size_t, - struct proc *); +char linux_sysname[128] = "Linux"; +#if defined(__i386__) || defined(__powerpc__) +char linux_release[128] = "2.4.18"; +char linux_version[128] = "#0 Wed Feb 20 20:00:02 CET 2002"; +#else +char linux_release[128] = "2.0.38"; +char linux_version[128] = "#0 Sun Nov 11 11:11:11 MET 2000"; #endif -int linux_dev_sysctl(int *, u_int, void *, size_t *, void *, size_t, - struct proc *); -int linux_bus_sysctl(int *, u_int, void *, size_t *, void *, size_t, - struct proc *); +static struct sysctlnode linux_sysctl_root = { + .sysctl_flags = SYSCTL_ROOT|CTLTYPE_NODE, + .sysctl_num = 0, + .sysctl_size = sizeof(struct sysctlnode), + .sysctl_name = "(linux_root)", +}; + +/* + * setup for small sysctl tree used by emulation + */ +SYSCTL_SETUP(linux_sysctl_setup, "linux emulated sysctl subtree setup") +{ + struct sysctlnode *rnode, *node; + + rnode = &linux_sysctl_root; + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_NODE, "kern", &rnode, + NULL, 0, NULL, 0, + LINUX_CTL_KERN, CTL_EOL); + + node = rnode; + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_STRING, "ostype", &node, + NULL, 0, linux_sysname, sizeof(linux_sysname), + LINUX_KERN_OSTYPE, CTL_EOL); + node = rnode; + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_STRING, "osrelease", &node, + NULL, 0, linux_release, sizeof(linux_release), + LINUX_KERN_OSRELEASE, CTL_EOL); + node = rnode; + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_STRING, "version", &node, + NULL, 0, linux_version, sizeof(linux_version), + LINUX_KERN_VERSION, CTL_EOL); +} + +/* + * linux sysctl system call + */ int linux_sys___sysctl(struct lwp *l, void *v, register_t *retval) { - struct linux_sys___sysctl_args /* { - syscallarg(struct linux___sysctl *) lsp; - } */ *uap = v; - struct proc *p = l->l_proc; + struct linux_sys___sysctl_args *uap = v; struct linux___sysctl ls; - int error; + int error, nerror, name[CTL_MAXNAME]; size_t savelen = 0, oldlen = 0; - sysctlfn *fn; - int name[CTL_MAXNAME]; - size_t *oldlenp; - - if ((error = copyin(SCARG(uap, lsp), &ls, sizeof ls))) + /* + * get linux args structure + */ + if ((error = copyin(SCARG(uap, lsp), &ls, sizeof(ls)))) return error; + + /* + * get oldlen + */ + oldlen = 0; + if (ls.oldlenp != NULL) { + error = copyin(ls.oldlenp, &oldlen, sizeof(oldlen)); + if (error) + return (error); + } + savelen = oldlen; + /* - * all top-level sysctl names are non-terminal + * top-level sysctl names may or may not be non-terminal, but + * we don't care */ - if (ls.nlen > CTL_MAXNAME || ls.nlen < 2) + if (ls.nlen > CTL_MAXNAME || ls.nlen < 1) return (EINVAL); error = copyin(ls.name, &name, ls.nlen * sizeof(int)); if (error) return (error); /* - * For all but CTL_PROC, must be root to change a value. - * For CTL_PROC, must be root, or owner of the proc (and not suid), - * this is checked in proc_sysctl() (once we know the targer proc). + * wire old so that copyout() is less likely to fail? */ - if (ls.newval != NULL && name[0] != CTL_PROC && - (error = suser(p->p_ucred, &p->p_acflag))) - return error; + error = sysctl_lock(l, ls.oldval, savelen); + if (error) + return (error); - switch (name[0]) { - case LINUX_CTL_KERN: - fn = linux_kern_sysctl; - break; - case LINUX_CTL_VM: - fn = linux_vm_sysctl; - break; - case LINUX_CTL_NET: - fn = linux_net_sysctl; - break; - case LINUX_CTL_PROC: - fn = linux_proc_sysctl; - break; - case LINUX_CTL_FS: - fn = linux_fs_sysctl; - break; -#ifdef DEBUG - case LINUX_CTL_DEBUG: - fn = linux_debug_sysctl; - break; -#endif - case LINUX_CTL_DEV: - fn = linux_dev_sysctl; - break; - case LINUX_CTL_BUS: - fn = linux_bus_sysctl; - break; - default: - return (EOPNOTSUPP); - } + /* + * dispatch request into linux sysctl tree + */ + error = sysctl_dispatch(&name[0], ls.nlen, + ls.oldval, &oldlen, + ls.newval, ls.newlen, + &name[0], l, &linux_sysctl_root); /* - * XXX Hey, we wire `oldval', but what about `newval'? + * release the sysctl lock */ - oldlenp = ls.oldlenp; - if (oldlenp) { - if ((error = copyin(oldlenp, &oldlen, sizeof(oldlen)))) - return (error); - oldlenp = &oldlen; - } - if (ls.oldval != NULL) { - error = uvm_vslock(p, ls.oldval, oldlen, - VM_PROT_READ|VM_PROT_WRITE); - savelen = oldlen; - } - error = (*fn)(name + 1, ls.nlen - 1, ls.oldval, oldlenp, ls.newval, - ls.newlen, p); - if (ls.oldval != NULL) - uvm_vsunlock(p, ls.oldval, savelen); - if (error) - return (error); - if (ls.oldlenp) - error = copyout(&oldlen, ls.oldlenp, sizeof(oldlen)); - return (error); -} + sysctl_unlock(l); -char linux_sysname[128] = "Linux"; -#if defined(__i386__) || defined(__powerpc__) -char linux_release[128] = "2.4.18"; -char linux_version[128] = "#0 Wed Feb 20 20:00:02 CET 2002"; -#else -char linux_release[128] = "2.0.38"; -char linux_version[128] = "#0 Sun Nov 11 11:11:11 MET 2000"; -#endif + /* + * lock state should now be only "needlock" and "canwait" + */ + /* XXX KASSERT */ -/* - * kernel related system variables. - */ -int -linux_kern_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) -{ /* - * Note that we allow writing into this, so that userland - * programs can setup things as they see fit. This is suboptimal. + * reset caller's oldlen, even if we got an error */ - switch (name[0]) { - case LINUX_KERN_OSTYPE: - return sysctl_string(oldp, oldlenp, newp, newlen, - linux_sysname, sizeof(linux_sysname)); - case LINUX_KERN_OSRELEASE: - return sysctl_string(oldp, oldlenp, newp, newlen, - linux_release, sizeof(linux_release)); - case LINUX_KERN_VERSION: - return sysctl_string(oldp, oldlenp, newp, newlen, - linux_version, sizeof(linux_version)); - default: - return EOPNOTSUPP; + if (ls.oldlenp) { + nerror = copyout(&oldlen, ls.oldlenp, sizeof(oldlen)); + if (error == 0) + error = nerror; } -} - -/* - * kernel related system variables. - */ -int -linux_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) -{ - if (nlen != 2 || name[0] != EMUL_LINUX_KERN) - return EOPNOTSUPP; /* - * Note that we allow writing into this, so that userland - * programs can setup things as they see fit. This is suboptimal. + * if the only problem is that we weren't given enough space, + * that's an ENOMEM error */ - switch (name[1]) { - case EMUL_LINUX_KERN_OSTYPE: - return sysctl_string(oldp, oldlenp, newp, newlen, - linux_sysname, sizeof(linux_sysname)); - case EMUL_LINUX_KERN_OSRELEASE: - return sysctl_string(oldp, oldlenp, newp, newlen, - linux_release, sizeof(linux_release)); - case EMUL_LINUX_KERN_VERSION: - return sysctl_string(oldp, oldlenp, newp, newlen, - linux_version, sizeof(linux_version)); - default: - return EOPNOTSUPP; - } + if (error == 0 && ls.oldval != NULL && savelen < oldlen) + error = ENOMEM; + + return (error); } /* - * hardware related system variables. + * kernel related system variables under emul.linux in the main sysctl + * tree */ -int -linux_vm_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) -{ - return (EOPNOTSUPP); -} - -int -linux_net_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) +SYSCTL_SETUP(sysctl_emul_linux_setup, "sysctl emul.linux subtree setup") { - return (EOPNOTSUPP); -} -int -linux_proc_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) -{ - return (EOPNOTSUPP); -} - -int -linux_fs_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) -{ - return (EOPNOTSUPP); -} -#ifdef DEBUG -int -linux_debug_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) -{ - return (EOPNOTSUPP); -} -#endif /* DEBUG */ - -int -linux_dev_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) -{ - return (EOPNOTSUPP); -} - -int -linux_bus_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen, struct proc *p) -{ - return (EOPNOTSUPP); + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_NODE, "emul", NULL, + NULL, 0, NULL, 0, + CTL_EMUL, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_NODE, "linux", NULL, + NULL, 0, NULL, 0, + CTL_EMUL, EMUL_LINUX, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_NODE, "kern", NULL, + NULL, 0, NULL, 0, + CTL_EMUL, EMUL_LINUX, EMUL_LINUX_KERN, CTL_EOL); + + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_STRING, "ostype", NULL, + NULL, 0, linux_sysname, sizeof(linux_sysname), + CTL_EMUL, EMUL_LINUX, EMUL_LINUX_KERN, + EMUL_LINUX_KERN_OSTYPE, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_STRING, "osrelease", NULL, + NULL, 0, linux_release, sizeof(linux_release), + CTL_EMUL, EMUL_LINUX, EMUL_LINUX_KERN, + EMUL_LINUX_KERN_OSRELEASE, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_STRING, "osversion", NULL, + NULL, 0, linux_version, sizeof(linux_version), + CTL_EMUL, EMUL_LINUX, EMUL_LINUX_KERN, + EMUL_LINUX_KERN_VERSION, CTL_EOL); } |
