xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 59314)
1 /*-
2  * Copyright (c) 1982, 1986, 1989, 1993 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Mike Karels at Berkeley Software Design, Inc.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)kern_sysctl.c	7.35 (Berkeley) 04/27/93
11  */
12 
13 /*
14  * sysctl system call.
15  */
16 
17 #include <sys/param.h>
18 #include <sys/systm.h>
19 #include <sys/malloc.h>
20 #include <sys/proc.h>
21 #include <sys/file.h>
22 #include <sys/vnode.h>
23 #include <sys/sysctl.h>
24 #include <sys/unistd.h>
25 #include <sys/buf.h>
26 #include <sys/ioctl.h>
27 #include <sys/tty.h>
28 
29 #include <vm/vm.h>
30 
31 #include <sys/kinfo_proc.h>
32 
33 sysctlfn kern_sysctl;
34 sysctlfn hw_sysctl;
35 #ifdef DEBUG
36 sysctlfn debug_sysctl;
37 #endif
38 extern sysctlfn vm_sysctl;
39 extern sysctlfn fs_sysctl;
40 extern sysctlfn net_sysctl;
41 extern sysctlfn cpu_sysctl;
42 
43 /*
44  * Locking and stats
45  */
46 static struct sysctl_lock {
47 	int	sl_lock;
48 	int	sl_want;
49 	int	sl_locked;
50 } memlock;
51 
52 struct sysctl_args {
53 	int	*name;
54 	u_int	namelen;
55 	void	*old;
56 	size_t	*oldlenp;
57 	void	*new;
58 	size_t	newlen;
59 };
60 
61 sysctl(p, uap, retval)
62 	struct proc *p;
63 	register struct sysctl_args *uap;
64 	int *retval;
65 {
66 	int error, dolock = 1;
67 	u_int savelen, oldlen = 0;
68 	sysctlfn *fn;
69 	int name[CTL_MAXNAME];
70 
71 	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
72 		return (error);
73 	/*
74 	 * all top-level sysctl names are non-terminal
75 	 */
76 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
77 		return (EINVAL);
78 	if (error = copyin(uap->name, &name, uap->namelen * sizeof(int)))
79 		return (error);
80 
81 	switch (name[0]) {
82 	case CTL_KERN:
83 		fn = kern_sysctl;
84 		if (name[2] != KERN_VNODE)	/* XXX */
85 			dolock = 0;
86 		break;
87 	case CTL_HW:
88 		fn = hw_sysctl;
89 		break;
90 	case CTL_VM:
91 		fn = vm_sysctl;
92 		break;
93 	case CTL_NET:
94 		fn = net_sysctl;
95 		break;
96 #ifdef notyet
97 	case CTL_FS:
98 		fn = fs_sysctl;
99 		break;
100 	case CTL_MACHDEP:
101 		fn = cpu_sysctl;
102 		break;
103 #endif
104 #ifdef DEBUG
105 	case CTL_DEBUG:
106 		fn = debug_sysctl;
107 		break;
108 #endif
109 	default:
110 		return (EOPNOTSUPP);
111 	}
112 
113 	if (uap->oldlenp &&
114 	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
115 		return (error);
116 	if (uap->old != NULL) {
117 		if (!useracc(uap->old, oldlen, B_WRITE))
118 			return (EFAULT);
119 		while (memlock.sl_lock) {
120 			memlock.sl_want = 1;
121 			sleep((caddr_t)&memlock, PRIBIO+1);
122 			memlock.sl_locked++;
123 		}
124 		memlock.sl_lock = 1;
125 		if (dolock)
126 			vslock(uap->old, oldlen);
127 		savelen = oldlen;
128 	}
129 	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
130 	    uap->new, uap->newlen, p);
131 	if (uap->old != NULL) {
132 		if (dolock)
133 			vsunlock(uap->old, savelen, B_WRITE);
134 		memlock.sl_lock = 0;
135 		if (memlock.sl_want) {
136 			memlock.sl_want = 0;
137 			wakeup((caddr_t)&memlock);
138 		}
139 	}
140 	if (error)
141 		return (error);
142 	if (uap->oldlenp)
143 		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
144 	*retval = oldlen;
145 	return (0);
146 }
147 
148 /*
149  * Attributes stored in the kernel.
150  */
151 char hostname[MAXHOSTNAMELEN];
152 int hostnamelen;
153 long hostid;
154 int securelevel;
155 
156 /*
157  * kernel related system variables.
158  */
159 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
160 	int *name;
161 	u_int namelen;
162 	void *oldp;
163 	size_t *oldlenp;
164 	void *newp;
165 	size_t newlen;
166 	struct proc *p;
167 {
168 	int error, level;
169 	extern char ostype[], osrelease[], version[];
170 
171 	/* all sysctl names at this level are terminal */
172 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
173 		return (ENOTDIR);		/* overloaded */
174 
175 	switch (name[0]) {
176 	case KERN_OSTYPE:
177 		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
178 	case KERN_OSRELEASE:
179 		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
180 	case KERN_OSREV:
181 		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
182 	case KERN_VERSION:
183 		return (sysctl_rdstring(oldp, oldlenp, newp, version));
184 	case KERN_POSIX1:
185 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
186 	case KERN_MAXPROC:
187 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
188 	case KERN_MAXFILES:
189 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
190 	case KERN_MAXVNODES:
191 		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
192 	case KERN_ARGMAX:
193 		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
194 	case KERN_HOSTNAME:
195 		error = sysctl_string(oldp, oldlenp, newp, newlen,
196 		    hostname, sizeof(hostname));
197 		if (!error)
198 			hostnamelen = newlen;
199 		return (error);
200 	case KERN_HOSTID:
201 		return (sysctl_int(oldp, oldlenp, newp, newlen, &hostid));
202 	case KERN_SECURELVL:
203 		level = securelevel;
204 		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
205 		    newp == NULL)
206 			return (error);
207 		if (level < securelevel && p->p_pid != 1)
208 			return (EPERM);
209 		securelevel = level;
210 		return (0);
211 	case KERN_CLOCKRATE:
212 		return (sysctl_clockrate(oldp, oldlenp));
213 	case KERN_FILE:
214 		return (sysctl_file(oldp, oldlenp));
215 	case KERN_VNODE:
216 		return (sysctl_vnode(oldp, oldlenp));
217 	case KERN_PROC:
218 		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
219 #ifdef GPROF
220 	case KERN_PROF:
221 		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
222 		    newp, newlen));
223 #endif
224 	default:
225 		return (EOPNOTSUPP);
226 	}
227 	/* NOTREACHED */
228 }
229 
230 /*
231  * hardware related system variables.
232  */
233 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
234 	int *name;
235 	u_int namelen;
236 	void *oldp;
237 	size_t *oldlenp;
238 	void *newp;
239 	size_t newlen;
240 	struct proc *p;
241 {
242 	extern char machine[], cpu_model[];
243 
244 	/* all sysctl names at this level are terminal */
245 	if (namelen != 1)
246 		return (ENOTDIR);		/* overloaded */
247 
248 	switch (name[0]) {
249 	case HW_MACHINE:
250 		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
251 	case HW_MODEL:
252 		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
253 	case HW_NCPU:
254 		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
255 	case HW_CPUSPEED:
256 		return (sysctl_rdint(oldp, oldlenp, newp, cpuspeed));
257 	case HW_PHYSMEM:
258 		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
259 	case HW_USERMEM:
260 		return (sysctl_rdint(oldp, oldlenp, newp,
261 		    ctob(physmem - cnt.v_wire_count)));
262 	case HW_PAGESIZE:
263 		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
264 	default:
265 		return (EOPNOTSUPP);
266 	}
267 	/* NOTREACHED */
268 }
269 
270 #ifdef DEBUG
271 /*
272  * Debugging related system variables.
273  */
274 struct ctldebug debug0, debug1, debug2, debug3, debug4;
275 struct ctldebug debug5, debug6, debug7, debug8, debug9;
276 struct ctldebug debug10, debug11, debug12, debug13, debug14;
277 struct ctldebug debug15, debug16, debug17, debug18, debug19;
278 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
279 	&debug0, &debug1, &debug2, &debug3, &debug4,
280 	&debug5, &debug6, &debug7, &debug8, &debug9,
281 	&debug10, &debug11, &debug12, &debug13, &debug14,
282 	&debug15, &debug16, &debug17, &debug18, &debug19,
283 };
284 int
285 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
286 	int *name;
287 	u_int namelen;
288 	void *oldp;
289 	size_t *oldlenp;
290 	void *newp;
291 	size_t newlen;
292 	struct proc *p;
293 {
294 	struct ctldebug *cdp;
295 
296 	/* all sysctl names at this level are name and field */
297 	if (namelen != 2)
298 		return (ENOTDIR);		/* overloaded */
299 	cdp = debugvars[name[0]];
300 	if (cdp->debugname == 0)
301 		return (EOPNOTSUPP);
302 	switch (name[1]) {
303 	case CTL_DEBUG_NAME:
304 		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
305 	case CTL_DEBUG_VALUE:
306 		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
307 	default:
308 		return (EOPNOTSUPP);
309 	}
310 	/* NOTREACHED */
311 }
312 #endif /* DEBUG */
313 
314 /*
315  * Validate parameters and get old / set new parameters
316  * for an integer-valued sysctl function.
317  */
318 sysctl_int(oldp, oldlenp, newp, newlen, valp)
319 	void *oldp;
320 	size_t *oldlenp;
321 	void *newp;
322 	size_t newlen;
323 	int *valp;
324 {
325 	int error = 0;
326 
327 	if (oldp && *oldlenp < sizeof(int))
328 		return (ENOMEM);
329 	if (newp && newlen != sizeof(int))
330 		return (EINVAL);
331 	*oldlenp = sizeof(int);
332 	if (oldp)
333 		error = copyout(valp, oldp, sizeof(int));
334 	if (error == 0 && newp)
335 		error = copyin(newp, valp, sizeof(int));
336 	return (error);
337 }
338 
339 /*
340  * As above, but read-only.
341  */
342 sysctl_rdint(oldp, oldlenp, newp, val)
343 	void *oldp;
344 	size_t *oldlenp;
345 	void *newp;
346 	int val;
347 {
348 	int error = 0;
349 
350 	if (oldp && *oldlenp < sizeof(int))
351 		return (ENOMEM);
352 	if (newp)
353 		return (EPERM);
354 	*oldlenp = sizeof(int);
355 	if (oldp)
356 		error = copyout((caddr_t)&val, oldp, sizeof(int));
357 	return (error);
358 }
359 
360 /*
361  * Validate parameters and get old / set new parameters
362  * for a string-valued sysctl function.
363  */
364 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
365 	void *oldp;
366 	size_t *oldlenp;
367 	void *newp;
368 	size_t newlen;
369 	char *str;
370 	int maxlen;
371 {
372 	int len, error = 0;
373 
374 	len = strlen(str) + 1;
375 	if (oldp && *oldlenp < len)
376 		return (ENOMEM);
377 	if (newp && newlen >= maxlen)
378 		return (EINVAL);
379 	if (oldp) {
380 		*oldlenp = len;
381 		error = copyout(str, oldp, len);
382 	}
383 	if (error == 0 && newp) {
384 		error = copyin(newp, str, newlen);
385 		str[newlen] = 0;
386 	}
387 	return (error);
388 }
389 
390 /*
391  * As above, but read-only.
392  */
393 sysctl_rdstring(oldp, oldlenp, newp, str)
394 	void *oldp;
395 	size_t *oldlenp;
396 	void *newp;
397 	char *str;
398 {
399 	int len, error = 0;
400 
401 	len = strlen(str) + 1;
402 	if (oldp && *oldlenp < len)
403 		return (ENOMEM);
404 	if (newp)
405 		return (EPERM);
406 	*oldlenp = len;
407 	if (oldp)
408 		error = copyout(str, oldp, len);
409 	return (error);
410 }
411 
412 /*
413  * Validate parameters and get old / set new parameters
414  * for a structure oriented sysctl function.
415  */
416 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
417 	void *oldp;
418 	size_t *oldlenp;
419 	void *newp;
420 	size_t newlen;
421 	void *sp;
422 	int len;
423 {
424 	int error = 0;
425 
426 	if (oldp && *oldlenp < len)
427 		return (ENOMEM);
428 	if (newp && newlen > len)
429 		return (EINVAL);
430 	if (oldp) {
431 		*oldlenp = len;
432 		error = copyout(sp, oldp, len);
433 	}
434 	if (error == 0 && newp)
435 		error = copyin(newp, sp, len);
436 	return (error);
437 }
438 
439 /*
440  * Validate parameters and get old parameters
441  * for a structure oriented sysctl function.
442  */
443 sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
444 	void *oldp;
445 	size_t *oldlenp;
446 	void *newp, *sp;
447 	int len;
448 {
449 	int error = 0;
450 
451 	if (oldp && *oldlenp < len)
452 		return (ENOMEM);
453 	if (newp)
454 		return (EPERM);
455 	*oldlenp = len;
456 	if (oldp)
457 		error = copyout(sp, oldp, len);
458 	return (error);
459 }
460 
461 /*
462  * Get file structures.
463  */
464 sysctl_file(where, sizep)
465 	char *where;
466 	size_t *sizep;
467 {
468 	int buflen, error;
469 	struct file *fp;
470 	char *start = where;
471 
472 	buflen = *sizep;
473 	if (where == NULL) {
474 		/*
475 		 * overestimate by 10 files
476 		 */
477 		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
478 		return (0);
479 	}
480 
481 	/*
482 	 * first copyout filehead
483 	 */
484 	if (buflen < sizeof(filehead)) {
485 		*sizep = 0;
486 		return (0);
487 	}
488 	if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
489 		return (error);
490 	buflen += sizeof(filehead);
491 	where += sizeof(filehead);
492 
493 	/*
494 	 * followed by an array of file structures
495 	 */
496 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
497 		if (buflen < sizeof(struct file)) {
498 			*sizep = where - start;
499 			return (ENOMEM);
500 		}
501 		if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
502 			return (error);
503 		buflen -= sizeof(struct file);
504 		where += sizeof(struct file);
505 	}
506 	*sizep = where - start;
507 	return (0);
508 }
509 
510 /*
511  * try over estimating by 5 procs
512  */
513 #define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
514 
515 sysctl_doproc(name, namelen, where, sizep)
516 	int *name;
517 	u_int namelen;
518 	char *where;
519 	size_t *sizep;
520 {
521 	register struct proc *p;
522 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
523 	register int needed = 0;
524 	int buflen = where != NULL ? *sizep : 0;
525 	int doingzomb;
526 	struct eproc eproc;
527 	int error = 0;
528 
529 	if (namelen != 2)
530 		return (EINVAL);
531 	p = (struct proc *)allproc;
532 	doingzomb = 0;
533 again:
534 	for (; p != NULL; p = p->p_nxt) {
535 		/*
536 		 * Skip embryonic processes.
537 		 */
538 		if (p->p_stat == SIDL)
539 			continue;
540 		/*
541 		 * TODO - make more efficient (see notes below).
542 		 * do by session.
543 		 */
544 		switch (name[0]) {
545 
546 		case KERN_PROC_PID:
547 			/* could do this with just a lookup */
548 			if (p->p_pid != (pid_t)name[1])
549 				continue;
550 			break;
551 
552 		case KERN_PROC_PGRP:
553 			/* could do this by traversing pgrp */
554 			if (p->p_pgrp->pg_id != (pid_t)name[1])
555 				continue;
556 			break;
557 
558 		case KERN_PROC_TTY:
559 			if ((p->p_flag&SCTTY) == 0 ||
560 			    p->p_session->s_ttyp == NULL ||
561 			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
562 				continue;
563 			break;
564 
565 		case KERN_PROC_UID:
566 			if (p->p_ucred->cr_uid != (uid_t)name[1])
567 				continue;
568 			break;
569 
570 		case KERN_PROC_RUID:
571 			if (p->p_cred->p_ruid != (uid_t)name[1])
572 				continue;
573 			break;
574 		}
575 		if (buflen >= sizeof(struct kinfo_proc)) {
576 			fill_eproc(p, &eproc);
577 			if (error = copyout((caddr_t)p, &dp->kp_proc,
578 			    sizeof(struct proc)))
579 				return (error);
580 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
581 			    sizeof(eproc)))
582 				return (error);
583 			dp++;
584 			buflen -= sizeof(struct kinfo_proc);
585 		}
586 		needed += sizeof(struct kinfo_proc);
587 	}
588 	if (doingzomb == 0) {
589 		p = zombproc;
590 		doingzomb++;
591 		goto again;
592 	}
593 	if (where != NULL) {
594 		*sizep = (caddr_t)dp - where;
595 		if (needed > *sizep)
596 			return (ENOMEM);
597 	} else {
598 		needed += KERN_PROCSLOP;
599 		*sizep = needed;
600 	}
601 	return (0);
602 }
603 
604 /*
605  * Fill in an eproc structure for the specified process.
606  */
607 void
608 fill_eproc(p, ep)
609 	register struct proc *p;
610 	register struct eproc *ep;
611 {
612 	register struct tty *tp;
613 
614 	ep->e_paddr = p;
615 	ep->e_sess = p->p_pgrp->pg_session;
616 	ep->e_pcred = *p->p_cred;
617 	ep->e_ucred = *p->p_ucred;
618 	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
619 		ep->e_vm.vm_rssize = 0;
620 		ep->e_vm.vm_tsize = 0;
621 		ep->e_vm.vm_dsize = 0;
622 		ep->e_vm.vm_ssize = 0;
623 #ifndef sparc
624 		/* ep->e_vm.vm_pmap = XXX; */
625 #endif
626 	} else {
627 		register struct vmspace *vm = p->p_vmspace;
628 
629 		ep->e_vm.vm_rssize = vm->vm_rssize;
630 		ep->e_vm.vm_tsize = vm->vm_tsize;
631 		ep->e_vm.vm_dsize = vm->vm_dsize;
632 		ep->e_vm.vm_ssize = vm->vm_ssize;
633 #ifndef sparc
634 		ep->e_vm.vm_pmap = vm->vm_pmap;
635 #endif
636 	}
637 	if (p->p_pptr)
638 		ep->e_ppid = p->p_pptr->p_pid;
639 	else
640 		ep->e_ppid = 0;
641 	ep->e_pgid = p->p_pgrp->pg_id;
642 	ep->e_jobc = p->p_pgrp->pg_jobc;
643 	if ((p->p_flag&SCTTY) &&
644 	     (tp = ep->e_sess->s_ttyp)) {
645 		ep->e_tdev = tp->t_dev;
646 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
647 		ep->e_tsess = tp->t_session;
648 	} else
649 		ep->e_tdev = NODEV;
650 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
651 	if (SESS_LEADER(p))
652 		ep->e_flag |= EPROC_SLEADER;
653 	if (p->p_wmesg)
654 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
655 	ep->e_xsize = ep->e_xrssize = 0;
656 	ep->e_xccount = ep->e_xswrss = 0;
657 }
658 
659 #ifdef COMPAT_43
660 #include <sys/socket.h>
661 #define	KINFO_PROC		(0<<8)
662 #define	KINFO_RT		(1<<8)
663 #define	KINFO_VNODE		(2<<8)
664 #define	KINFO_FILE		(3<<8)
665 #define	KINFO_METER		(4<<8)
666 #define	KINFO_LOADAVG		(5<<8)
667 #define	KINFO_CLOCKRATE		(6<<8)
668 
669 struct getkerninfo_args {
670 	int	op;
671 	char	*where;
672 	int	*size;
673 	int	arg;
674 };
675 
676 ogetkerninfo(p, uap, retval)
677 	struct proc *p;
678 	register struct getkerninfo_args *uap;
679 	int *retval;
680 {
681 	int error, name[5];
682 	u_int size;
683 
684 	if (uap->size &&
685 	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
686 		return (error);
687 
688 	switch (uap->op & 0xff00) {
689 
690 	case KINFO_RT:
691 		name[0] = PF_ROUTE;
692 		name[1] = 0;
693 		name[2] = (uap->op & 0xff0000) >> 16;
694 		name[3] = uap->op & 0xff;
695 		name[4] = uap->arg;
696 		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
697 		break;
698 
699 	case KINFO_VNODE:
700 		name[0] = KERN_VNODE;
701 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
702 		break;
703 
704 	case KINFO_PROC:
705 		name[0] = KERN_PROC;
706 		name[1] = uap->op & 0xff;
707 		name[2] = uap->arg;
708 		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
709 		break;
710 
711 	case KINFO_FILE:
712 		name[0] = KERN_FILE;
713 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
714 		break;
715 
716 	case KINFO_METER:
717 		name[0] = VM_METER;
718 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
719 		break;
720 
721 	case KINFO_LOADAVG:
722 		name[0] = VM_LOADAVG;
723 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
724 		break;
725 
726 	case KINFO_CLOCKRATE:
727 		name[0] = KERN_CLOCKRATE;
728 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
729 		break;
730 
731 	default:
732 		return (EOPNOTSUPP);
733 	}
734 	if (error)
735 		return (error);
736 	*retval = size;
737 	if (uap->size)
738 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
739 		    sizeof(size));
740 	return (error);
741 }
742 #endif /* COMPAT_43 */
743