diff options
author | nate <nate@FreeBSD.org> | 1996-06-10 16:23:42 +0000 |
---|---|---|
committer | nate <nate@FreeBSD.org> | 1996-06-10 16:23:42 +0000 |
commit | 68b3f1ce70e0dec9ed0b3454f40628b409196f2d (patch) | |
tree | fac0a614ca641dfd02698e370948ecda7255db86 /sys/kern/kern_sysctl.c | |
parent | 6ae6d3340ac8335cf0acd5587e8bd8fa075656ba (diff) | |
download | FreeBSD-src-68b3f1ce70e0dec9ed0b3454f40628b409196f2d.zip FreeBSD-src-68b3f1ce70e0dec9ed0b3454f40628b409196f2d.tar.gz |
Implemented 'kern_sysctl', which differs from 'userland_sysctl' in that
it assumes all of the data exists in the kernel. Also, fix
sysctl_new-kernel (unused until now) which had reversed operands to
bcopy().
Reviewed by: phk
Poul writes:
... actually the lock/sleep/wakeup cruft shouldn't be needed in the
kernel version I think, but just leave it there for now.
Diffstat (limited to 'sys/kern/kern_sysctl.c')
-rw-r--r-- | sys/kern/kern_sysctl.c | 68 |
1 files changed, 63 insertions, 5 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 51c78b9..1d26922 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 - * $Id: kern_sysctl.c,v 1.62 1996/04/13 13:28:54 phk Exp $ + * $Id: kern_sysctl.c,v 1.63 1996/06/06 17:17:54 phk Exp $ */ #include <sys/param.h> @@ -571,24 +571,82 @@ sysctl_old_kernel(struct sysctl_req *req, const void *p, int l) bcopy(p, req->oldptr + req->oldidx, i); } req->oldidx += l; - if (i != l) + if (req->oldptr && i != l) return (ENOMEM); return (0); - } static int -sysctl_new_kernel(struct sysctl_req *req, const void *p, int l) +sysctl_new_kernel(struct sysctl_req *req, void *p, int l) { if (!req->newptr) return 0; if (req->newlen - req->newidx < l) return (EINVAL); - bcopy(p, req->newptr + req->newidx, l); + bcopy(req->newptr + req->newidx, p, l); req->newidx += l; return (0); } +int +kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, int *retval) +{ + int error = 0; + struct sysctl_req req; + + bzero(&req, sizeof req); + + req.p = p; + + if (oldlenp) { + req.oldlen = *oldlenp; + } + + if (old) { + req.oldptr= old; + } + + if (newlen) { + req.newlen = newlen; + req.newptr = new; + } + + req.oldfunc = sysctl_old_kernel; + req.newfunc = sysctl_new_kernel; + 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 (retval) { + if (req.oldptr && req.oldidx > req.oldlen) + *retval = req.oldlen; + else + *retval = req.oldidx; + } + return (error); +} + /* * Transfer function to/from user space. */ |