diff options
| author | Poul-Henning Kamp <phk@FreeBSD.org> | 1995-11-20 12:42:39 +0000 |
|---|---|---|
| committer | Poul-Henning Kamp <phk@FreeBSD.org> | 1995-11-20 12:42:39 +0000 |
| commit | 4b2af45f4ba1f8d8d5a56c4b18f29da6d08146e9 (patch) | |
| tree | 3c18ee3a32f49eafefcfca9b38f0533552958ab7 /sys/kern/kern_sysctl.c | |
| parent | fe66bbf4885ee0f3139abafc77baa90493c18a69 (diff) | |
Notes
Diffstat (limited to 'sys/kern/kern_sysctl.c')
| -rw-r--r-- | sys/kern/kern_sysctl.c | 473 |
1 files changed, 107 insertions, 366 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 27b55a75dd93..5c3332b545d3 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 - * $Id: kern_sysctl.c,v 1.50 1995/11/14 20:43:29 phk Exp $ + * $Id: kern_sysctl.c,v 1.51 1995/11/16 18:59:49 phk Exp $ */ /* @@ -50,6 +50,17 @@ #include <sys/conf.h> #include <sys/sysctl.h> +/* + * Locking and stats + */ +static struct sysctl_lock { + int sl_lock; + int sl_want; + int sl_locked; +} memlock; + +static int sysctl_root SYSCTL_HANDLER_ARGS; + extern struct linker_set sysctl_; /* BEGIN_MIB */ @@ -145,6 +156,66 @@ char hostname[MAXHOSTNAMELEN]; SYSCTL_STRING(_kern, KERN_HOSTNAME, hostname, CTLFLAG_RW, hostname, sizeof(hostname), ""); +int securelevel = -1; + +static int +sysctl_kern_securelvl SYSCTL_HANDLER_ARGS +{ + int error, level; + + level = securelevel; + error = sysctl_handle_int(oidp, &level, 0, req); + if (error || !req->newptr) + return (error); + if (level < securelevel && req->p->p_pid != 1) + return (EPERM); + securelevel = level; + return (error); +} + +SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW, + 0, 0, sysctl_kern_securelvl, ""); + +static int +sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS +{ + int error; + dev_t ndumpdev; + + ndumpdev = dumpdev; + error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req); + if (!error && ndumpdev != dumpdev) { + error = setdumpdev(ndumpdev); + } + return (error); +} + +SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, + 0, sizeof dumpdev, sysctl_kern_dumpdev, ""); + +static int +sysctl_hw_physmem SYSCTL_HANDLER_ARGS +{ + int error = sysctl_handle_int(oidp, 0, ctob(physmem), req); + return (error); +} + +SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD, + 0, 0, sysctl_hw_physmem, ""); + +static int +sysctl_hw_usermem SYSCTL_HANDLER_ARGS +{ + int error = sysctl_handle_int(oidp, 0, + ctob(physmem - cnt.v_wire_count), req); + return (error); +} + +SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD, + 0, 0, sysctl_hw_usermem, ""); + +/* END_MIB */ + static int sysctl_order_cmp(const void *a, const void *b) { @@ -370,6 +441,10 @@ sysctl_old_user(struct sysctl_req *req, void *p, int l) { int error = 0, i = 0; + if (req->lock == 1 && req->oldptr) { + vslock(req->oldptr, req->oldlen); + req->lock = 2; + } if (req->oldptr) { i = min(req->oldlen - req->oldidx, l); if (i > 0) @@ -398,23 +473,10 @@ sysctl_new_user(struct sysctl_req *req, void *p, int l) } /* - * Locking and stats - */ -static struct sysctl_lock { - int sl_lock; - int sl_want; - int sl_locked; -} memlock; - - - -/* * Traverse our tree, and find the right node, execute whatever it points * at, and return the resulting error code. - * We work entirely in kernel-space at this time. */ - int sysctl_root SYSCTL_HANDLER_ARGS { @@ -431,6 +493,8 @@ sysctl_root SYSCTL_HANDLER_ARGS while (j-- && indx < CTL_MAXNAME) { if (*oidpp && ((*oidpp)->oid_number == name[indx])) { indx++; + if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK) + req->lock = 0; if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { if ((*oidpp)->oid_handler) goto found; @@ -482,10 +546,7 @@ struct sysctl_args { #endif int -__sysctl(p, uap, retval) - struct proc *p; - register struct sysctl_args *uap; - int *retval; +__sysctl(struct proc *p, struct sysctl_args *uap, int *retval) { int error, i, j, name[CTL_MAXNAME]; @@ -509,8 +570,6 @@ __sysctl(p, uap, retval) return (error); } -static sysctlfn kern_sysctl; - /* * This is used from various compatibility syscalls too. That's why name * must be in kernel space. @@ -518,9 +577,7 @@ static sysctlfn kern_sysctl; int userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval) { - int error = 0, dolock = 1, oldlen = 0; - u_int savelen = 0; - sysctlfn *fn; + int error = 0; struct sysctl_req req; bzero(&req, sizeof req); @@ -555,15 +612,30 @@ userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *old req.oldfunc = sysctl_old_user; req.newfunc = sysctl_new_user; + req.lock = 1; + + /* XXX this should probably be done in a general way */ + while (memlock.sl_lock) { + memlock.sl_want = 1; + (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); + memlock.sl_locked++; + } + memlock.sl_lock = 1; error = sysctl_root(0, name, namelen, &req); -/* + if (req.lock == 2) + vsunlock(req.oldptr, req.oldlen, B_WRITE); + + memlock.sl_lock = 0; + + if (memlock.sl_want) { + memlock.sl_want = 0; + wakeup((caddr_t)&memlock); + } + if (error && error != ENOMEM) return (error); -*/ - if (error == ENOENT) - goto oldstuff; if (retval) { if (req.oldptr && req.oldidx > req.oldlen) @@ -572,334 +644,6 @@ userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *old *retval = req.oldidx; } return (error); - -oldstuff: - oldlen = req.oldlen; - - switch (name[0]) { - case CTL_KERN: - fn = kern_sysctl; - if (name[1] != KERN_VNODE) /* XXX */ - dolock = 0; - break; - case CTL_HW: - fn = hw_sysctl; - break; - case CTL_FS: - fn = fs_sysctl; - break; - default: - return (EOPNOTSUPP); - } - if (old != NULL) { - if (!useracc(old, oldlen, B_WRITE)) - return (EFAULT); - while (memlock.sl_lock) { - memlock.sl_want = 1; - (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); - memlock.sl_locked++; - } - memlock.sl_lock = 1; - if (dolock) - vslock(old, oldlen); - savelen = oldlen; - } - - - error = (*fn)(name + 1, namelen - 1, old, &oldlen, - new, newlen, p); - - - if (old != NULL) { - if (dolock) - vsunlock(old, savelen, B_WRITE); - memlock.sl_lock = 0; - if (memlock.sl_want) { - memlock.sl_want = 0; - wakeup((caddr_t)&memlock); - } - } -#if 0 - if (error) { - printf("SYSCTL_ERROR: "); - for(i=0;i<namelen;i++) - printf("%d ", name[i]); - printf("= %d\n", error); - } -#endif - if (error) - return (error); - if (retval) - *retval = oldlen; - return (error); -} - -/* - * Attributes stored in the kernel. - */ -int securelevel = -1; - -/* - * kernel related system variables. - */ -static int -kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; - struct proc *p; -{ - - /* all sysctl names at this level are terminal */ - if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF - || name[0] == KERN_NTP_PLL)) - return (ENOTDIR); /* overloaded */ - - switch (name[0]) { - - case KERN_VNODE: - return (sysctl_vnode(oldp, oldlenp)); -#ifdef GPROF - case KERN_PROF: - return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, - newp, newlen)); -#endif - default: - return (EOPNOTSUPP); - } - /* NOTREACHED */ -} - -static int -sysctl_kern_securelvl SYSCTL_HANDLER_ARGS -{ - int error, level; - - level = securelevel; - error = sysctl_handle_int(oidp, &level, 0, req); - if (error || !req->newptr) - return (error); - if (level < securelevel && req->p->p_pid != 1) - return (EPERM); - securelevel = level; - return (error); -} - -SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW, - 0, 0, sysctl_kern_securelvl, ""); - -static int -sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS -{ - int error; - dev_t ndumpdev; - - ndumpdev = dumpdev; - error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req); - if (!error && ndumpdev != dumpdev) { - error = setdumpdev(ndumpdev); - } - return (error); -} - -SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, - 0, sizeof dumpdev, sysctl_kern_dumpdev, ""); -/* - * hardware related system variables. - */ -int -hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; - struct proc *p; -{ - /* almost all sysctl names at this level are terminal */ - if (namelen != 1 && name[0] != HW_DEVCONF) - return (ENOTDIR); /* overloaded */ - - switch (name[0]) { - case HW_PHYSMEM: - return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); - case HW_USERMEM: - return (sysctl_rdint(oldp, oldlenp, newp, - ctob(physmem - cnt.v_wire_count))); - case HW_DEVCONF: - return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp, - newp, newlen, p)); - default: - return (EOPNOTSUPP); - } - /* NOTREACHED */ -} - -/* - * Validate parameters and get old / set new parameters - * for an integer-valued sysctl function. - */ -int -sysctl_int(oldp, oldlenp, newp, newlen, valp) - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; - int *valp; -{ - int error = 0; - - if (oldp && *oldlenp < sizeof(int)) - return (ENOMEM); - if (newp && newlen != sizeof(int)) - return (EINVAL); - *oldlenp = sizeof(int); - if (oldp) - error = copyout(valp, oldp, sizeof(int)); - if (error == 0 && newp) - error = copyin(newp, valp, sizeof(int)); - return (error); -} - -/* - * As above, but read-only. - */ -int -sysctl_rdint(oldp, oldlenp, newp, val) - void *oldp; - size_t *oldlenp; - void *newp; - int val; -{ - int error = 0; - - if (oldp && *oldlenp < sizeof(int)) - return (ENOMEM); - if (newp) - return (EPERM); - *oldlenp = sizeof(int); - if (oldp) - error = copyout((caddr_t)&val, oldp, sizeof(int)); - return (error); -} - -/* - * Validate parameters and get old / set new parameters - * for a string-valued sysctl function. - */ -int -sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; - char *str; - int maxlen; -{ - int len, error = 0, rval = 0; - - len = strlen(str) + 1; - if (oldp && *oldlenp < len) { - len = *oldlenp; - rval = ENOMEM; - } - if (newp && newlen >= maxlen) - return (EINVAL); - if (oldp) { - *oldlenp = len; - error = copyout(str, oldp, len); - if (error) - rval = error; - } - if ((error == 0 || error == ENOMEM) && newp) { - error = copyin(newp, str, newlen); - if (error) - rval = error; - str[newlen] = 0; - } - return (rval); -} - -/* - * As above, but read-only. - */ -int -sysctl_rdstring(oldp, oldlenp, newp, str) - void *oldp; - size_t *oldlenp; - void *newp; - char *str; -{ - int len, error = 0, rval = 0; - - len = strlen(str) + 1; - if (oldp && *oldlenp < len) { - len = *oldlenp; - rval = ENOMEM; - } - if (newp) - return (EPERM); - *oldlenp = len; - if (oldp) - error = copyout(str, oldp, len); - if (error) - rval = error; - return (rval); -} - -/* - * Validate parameters and get old / set new parameters - * for a structure oriented sysctl function. - */ -int -sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; - void *sp; - int len; -{ - int error = 0; - - if (oldp && *oldlenp < len) - return (ENOMEM); - if (newp && newlen > len) - return (EINVAL); - if (oldp) { - *oldlenp = len; - error = copyout(sp, oldp, len); - } - if (error == 0 && newp) - error = copyin(newp, sp, len); - return (error); -} - -/* - * Validate parameters and get old parameters - * for a structure oriented sysctl function. - */ -int -sysctl_rdstruct(oldp, oldlenp, newp, sp, len) - void *oldp; - size_t *oldlenp; - void *newp, *sp; - int len; -{ - int error = 0; - - if (oldp && *oldlenp < len) - return (ENOMEM); - if (newp) - return (EPERM); - *oldlenp = len; - if (oldp) - error = copyout(sp, oldp, len); - return (error); } #ifdef COMPAT_43 @@ -969,10 +713,7 @@ struct getkerninfo_args { #endif int -ogetkerninfo(p, uap, retval) - struct proc *p; - register struct getkerninfo_args *uap; - int *retval; +ogetkerninfo(struct proc *p, struct getkerninfo_args *uap, int *retval) { int error, name[6]; u_int size; @@ -987,14 +728,14 @@ ogetkerninfo(p, uap, retval) name[4] = uap->op & 0xff; name[5] = uap->arg; error = userland_sysctl(p, name, 6, uap->where, uap->size, - 0, 0, 0, 0); + 0, 0, 0, &size); break; case KINFO_VNODE: name[0] = CTL_KERN; name[1] = KERN_VNODE; error = userland_sysctl(p, name, 2, uap->where, uap->size, - 0, 0, 0, 0); + 0, 0, 0, &size); break; case KINFO_PROC: @@ -1003,35 +744,35 @@ ogetkerninfo(p, uap, retval) name[2] = uap->op & 0xff; name[3] = uap->arg; error = userland_sysctl(p, name, 4, uap->where, uap->size, - 0, 0, 0, 0); + 0, 0, 0, &size); break; case KINFO_FILE: name[0] = CTL_KERN; name[1] = KERN_FILE; error = userland_sysctl(p, name, 2, uap->where, uap->size, - 0, 0, 0, 0); + 0, 0, 0, &size); break; case KINFO_METER: name[0] = CTL_VM; name[1] = VM_METER; error = userland_sysctl(p, name, 2, uap->where, uap->size, - 0, 0, 0, 0); + 0, 0, 0, &size); break; case KINFO_LOADAVG: name[0] = CTL_VM; name[1] = VM_LOADAVG; error = userland_sysctl(p, name, 2, uap->where, uap->size, - 0, 0, 0, 0); + 0, 0, 0, &size); break; case KINFO_CLOCKRATE: name[0] = CTL_KERN; name[1] = KERN_CLOCKRATE; error = userland_sysctl(p, name, 2, uap->where, uap->size, - 0, 0, 0, 0); + 0, 0, 0, &size); break; case KINFO_BSDI_SYSINFO: { |
