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