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