/* $NetBSD: linux_sysctl.c,v 1.5 2002/04/04 09:32:11 tron Exp $ */ /*- * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Mike Karels at Berkeley Software Design, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. * * 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 */ /* * sysctl system call. */ #include __KERNEL_RCSID(0, "$NetBSD: linux_sysctl.c,v 1.5 2002/04/04 09:32:11 tron Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include 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 *); #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 *); int linux_sys___sysctl(struct proc *p, void *v, register_t *retval) { struct linux_sys___sysctl_args /* { syscallarg(struct linux___sysctl *) lsp; } */ *uap = v; struct linux___sysctl ls; int error; size_t savelen = 0, oldlen = 0; sysctlfn *fn; int name[CTL_MAXNAME]; size_t *oldlenp; if ((error = copyin(SCARG(uap, lsp), &ls, sizeof ls))) return error; /* * all top-level sysctl names are non-terminal */ if (ls.nlen > CTL_MAXNAME || ls.nlen < 2) 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). */ if (ls.newval != NULL && name[0] != CTL_PROC && (error = suser(p->p_ucred, &p->p_acflag))) 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); } /* * XXX Hey, we wire `oldval', but what about `newval'? */ 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); } char linux_sysname[128] = "Linux"; #ifdef __i386__ 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 /* * 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. */ 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; } } /* * 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. */ 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; } } /* * hardware related system variables. */ 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) { 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); }