xref: /freebsd/sys/kern/kern_sysctl.c (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
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  * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
9  * project, to make these variables more userfriendly.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
36  */
37 
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40 
41 #include "opt_compat.h"
42 #include "opt_mac.h"
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/sysctl.h>
48 #include <sys/mac.h>
49 #include <sys/malloc.h>
50 #include <sys/proc.h>
51 #include <sys/lock.h>
52 #include <sys/mutex.h>
53 #include <sys/sx.h>
54 #include <sys/sysproto.h>
55 #include <vm/vm.h>
56 #include <vm/vm_extern.h>
57 
58 static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
59 static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
60 static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
61 
62 /*
63  * Locking - this locks the sysctl tree in memory.
64  */
65 static struct sx sysctllock;
66 
67 #define	SYSCTL_LOCK()		sx_xlock(&sysctllock)
68 #define	SYSCTL_UNLOCK()		sx_xunlock(&sysctllock)
69 #define	SYSCTL_INIT()		sx_init(&sysctllock, "sysctl lock")
70 
71 static int sysctl_root(SYSCTL_HANDLER_ARGS);
72 
73 struct sysctl_oid_list sysctl__children; /* root list */
74 
75 static struct sysctl_oid *
76 sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
77 {
78 	struct sysctl_oid *oidp;
79 
80 	SLIST_FOREACH(oidp, list, oid_link) {
81 		if (strcmp(oidp->oid_name, name) == 0) {
82 			return (oidp);
83 		}
84 	}
85 	return (NULL);
86 }
87 
88 /*
89  * Initialization of the MIB tree.
90  *
91  * Order by number in each list.
92  */
93 
94 void
95 sysctl_register_oid(struct sysctl_oid *oidp)
96 {
97 	struct sysctl_oid_list *parent = oidp->oid_parent;
98 	struct sysctl_oid *p;
99 	struct sysctl_oid *q;
100 
101 	/*
102 	 * First check if another oid with the same name already
103 	 * exists in the parent's list.
104 	 */
105 	p = sysctl_find_oidname(oidp->oid_name, parent);
106 	if (p != NULL) {
107 		if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
108 			p->oid_refcnt++;
109 			return;
110 		} else {
111 			printf("can't re-use a leaf (%s)!\n", p->oid_name);
112 			return;
113 		}
114 	}
115 	/*
116 	 * If this oid has a number OID_AUTO, give it a number which
117 	 * is greater than any current oid.
118 	 * NOTE: DO NOT change the starting value here, change it in
119 	 * <sys/sysctl.h>, and make sure it is at least 256 to
120 	 * accomodate e.g. net.inet.raw as a static sysctl node.
121 	 */
122 	if (oidp->oid_number == OID_AUTO) {
123 		static int newoid = CTL_AUTO_START;
124 
125 		oidp->oid_number = newoid++;
126 		if (newoid == 0x7fffffff)
127 			panic("out of oids");
128 	}
129 #if 0
130 	else if (oidp->oid_number >= CTL_AUTO_START) {
131 		/* do not panic; this happens when unregistering sysctl sets */
132 		printf("static sysctl oid too high: %d", oidp->oid_number);
133 	}
134 #endif
135 
136 	/*
137 	 * Insert the oid into the parent's list in order.
138 	 */
139 	q = NULL;
140 	SLIST_FOREACH(p, parent, oid_link) {
141 		if (oidp->oid_number < p->oid_number)
142 			break;
143 		q = p;
144 	}
145 	if (q)
146 		SLIST_INSERT_AFTER(q, oidp, oid_link);
147 	else
148 		SLIST_INSERT_HEAD(parent, oidp, oid_link);
149 }
150 
151 void
152 sysctl_unregister_oid(struct sysctl_oid *oidp)
153 {
154 	struct sysctl_oid *p;
155 	int error;
156 
157 	error = ENOENT;
158 	if (oidp->oid_number == OID_AUTO) {
159 		error = EINVAL;
160 	} else {
161 		SLIST_FOREACH(p, oidp->oid_parent, oid_link) {
162 			if (p == oidp) {
163 				SLIST_REMOVE(oidp->oid_parent, oidp,
164 				    sysctl_oid, oid_link);
165 				error = 0;
166 				break;
167 			}
168 		}
169 	}
170 
171 	/*
172 	 * This can happen when a module fails to register and is
173 	 * being unloaded afterwards.  It should not be a panic()
174 	 * for normal use.
175 	 */
176 	if (error)
177 		printf("%s: failed to unregister sysctl\n", __func__);
178 }
179 
180 /* Initialize a new context to keep track of dynamically added sysctls. */
181 int
182 sysctl_ctx_init(struct sysctl_ctx_list *c)
183 {
184 
185 	if (c == NULL) {
186 		return (EINVAL);
187 	}
188 	TAILQ_INIT(c);
189 	return (0);
190 }
191 
192 /* Free the context, and destroy all dynamic oids registered in this context */
193 int
194 sysctl_ctx_free(struct sysctl_ctx_list *clist)
195 {
196 	struct sysctl_ctx_entry *e, *e1;
197 	int error;
198 
199 	error = 0;
200 	/*
201 	 * First perform a "dry run" to check if it's ok to remove oids.
202 	 * XXX FIXME
203 	 * XXX This algorithm is a hack. But I don't know any
204 	 * XXX better solution for now...
205 	 */
206 	TAILQ_FOREACH(e, clist, link) {
207 		error = sysctl_remove_oid(e->entry, 0, 0);
208 		if (error)
209 			break;
210 	}
211 	/*
212 	 * Restore deregistered entries, either from the end,
213 	 * or from the place where error occured.
214 	 * e contains the entry that was not unregistered
215 	 */
216 	if (error)
217 		e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
218 	else
219 		e1 = TAILQ_LAST(clist, sysctl_ctx_list);
220 	while (e1 != NULL) {
221 		sysctl_register_oid(e1->entry);
222 		e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
223 	}
224 	if (error)
225 		return(EBUSY);
226 	/* Now really delete the entries */
227 	e = TAILQ_FIRST(clist);
228 	while (e != NULL) {
229 		e1 = TAILQ_NEXT(e, link);
230 		error = sysctl_remove_oid(e->entry, 1, 0);
231 		if (error)
232 			panic("sysctl_remove_oid: corrupt tree, entry: %s",
233 			    e->entry->oid_name);
234 		free(e, M_SYSCTLOID);
235 		e = e1;
236 	}
237 	return (error);
238 }
239 
240 /* Add an entry to the context */
241 struct sysctl_ctx_entry *
242 sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
243 {
244 	struct sysctl_ctx_entry *e;
245 
246 	if (clist == NULL || oidp == NULL)
247 		return(NULL);
248 	e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
249 	e->entry = oidp;
250 	TAILQ_INSERT_HEAD(clist, e, link);
251 	return (e);
252 }
253 
254 /* Find an entry in the context */
255 struct sysctl_ctx_entry *
256 sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
257 {
258 	struct sysctl_ctx_entry *e;
259 
260 	if (clist == NULL || oidp == NULL)
261 		return(NULL);
262 	TAILQ_FOREACH(e, clist, link) {
263 		if(e->entry == oidp)
264 			return(e);
265 	}
266 	return (e);
267 }
268 
269 /*
270  * Delete an entry from the context.
271  * NOTE: this function doesn't free oidp! You have to remove it
272  * with sysctl_remove_oid().
273  */
274 int
275 sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
276 {
277 	struct sysctl_ctx_entry *e;
278 
279 	if (clist == NULL || oidp == NULL)
280 		return (EINVAL);
281 	e = sysctl_ctx_entry_find(clist, oidp);
282 	if (e != NULL) {
283 		TAILQ_REMOVE(clist, e, link);
284 		free(e, M_SYSCTLOID);
285 		return (0);
286 	} else
287 		return (ENOENT);
288 }
289 
290 /*
291  * Remove dynamically created sysctl trees.
292  * oidp - top of the tree to be removed
293  * del - if 0 - just deregister, otherwise free up entries as well
294  * recurse - if != 0 traverse the subtree to be deleted
295  */
296 int
297 sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
298 {
299 	struct sysctl_oid *p;
300 	int error;
301 
302 	if (oidp == NULL)
303 		return(EINVAL);
304 	if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
305 		printf("can't remove non-dynamic nodes!\n");
306 		return (EINVAL);
307 	}
308 	/*
309 	 * WARNING: normal method to do this should be through
310 	 * sysctl_ctx_free(). Use recursing as the last resort
311 	 * method to purge your sysctl tree of leftovers...
312 	 * However, if some other code still references these nodes,
313 	 * it will panic.
314 	 */
315 	if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
316 		if (oidp->oid_refcnt == 1) {
317 			SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
318 				if (!recurse)
319 					return (ENOTEMPTY);
320 				error = sysctl_remove_oid(p, del, recurse);
321 				if (error)
322 					return (error);
323 			}
324 			if (del)
325 				free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
326 		}
327 	}
328 	if (oidp->oid_refcnt > 1 ) {
329 		oidp->oid_refcnt--;
330 	} else {
331 		if (oidp->oid_refcnt == 0) {
332 			printf("Warning: bad oid_refcnt=%u (%s)!\n",
333 				oidp->oid_refcnt, oidp->oid_name);
334 			return (EINVAL);
335 		}
336 		sysctl_unregister_oid(oidp);
337 		if (del) {
338 			if (oidp->descr)
339 				free((void *)(uintptr_t)(const void *)oidp->descr, M_SYSCTLOID);
340 			free((void *)(uintptr_t)(const void *)oidp->oid_name,
341 			     M_SYSCTLOID);
342 			free(oidp, M_SYSCTLOID);
343 		}
344 	}
345 	return (0);
346 }
347 
348 /*
349  * Create new sysctls at run time.
350  * clist may point to a valid context initialized with sysctl_ctx_init().
351  */
352 struct sysctl_oid *
353 sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
354 	int number, const char *name, int kind, void *arg1, int arg2,
355 	int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
356 {
357 	struct sysctl_oid *oidp;
358 	ssize_t len;
359 	char *newname;
360 
361 	/* You have to hook up somewhere.. */
362 	if (parent == NULL)
363 		return(NULL);
364 	/* Check if the node already exists, otherwise create it */
365 	oidp = sysctl_find_oidname(name, parent);
366 	if (oidp != NULL) {
367 		if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
368 			oidp->oid_refcnt++;
369 			/* Update the context */
370 			if (clist != NULL)
371 				sysctl_ctx_entry_add(clist, oidp);
372 			return (oidp);
373 		} else {
374 			printf("can't re-use a leaf (%s)!\n", name);
375 			return (NULL);
376 		}
377 	}
378 	oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO);
379 	oidp->oid_parent = parent;
380 	SLIST_NEXT(oidp, oid_link) = NULL;
381 	oidp->oid_number = number;
382 	oidp->oid_refcnt = 1;
383 	len = strlen(name);
384 	newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
385 	bcopy(name, newname, len + 1);
386 	newname[len] = '\0';
387 	oidp->oid_name = newname;
388 	oidp->oid_handler = handler;
389 	oidp->oid_kind = CTLFLAG_DYN | kind;
390 	if ((kind & CTLTYPE) == CTLTYPE_NODE) {
391 		/* Allocate space for children */
392 		SYSCTL_CHILDREN_SET(oidp, malloc(sizeof(struct sysctl_oid_list),
393 		    M_SYSCTLOID, M_WAITOK));
394 		SLIST_INIT(SYSCTL_CHILDREN(oidp));
395 	} else {
396 		oidp->oid_arg1 = arg1;
397 		oidp->oid_arg2 = arg2;
398 	}
399 	oidp->oid_fmt = fmt;
400 	if (descr) {
401 		int len = strlen(descr) + 1;
402 		oidp->descr = malloc(len, M_SYSCTLOID, M_WAITOK);
403 		if (oidp->descr)
404 			strcpy((char *)(uintptr_t)(const void *)oidp->descr, descr);
405 	}
406 	/* Update the context, if used */
407 	if (clist != NULL)
408 		sysctl_ctx_entry_add(clist, oidp);
409 	/* Register this oid */
410 	sysctl_register_oid(oidp);
411 	return (oidp);
412 }
413 
414 /*
415  * Reparent an existing oid.
416  */
417 int
418 sysctl_move_oid(struct sysctl_oid *oid, struct sysctl_oid_list *parent)
419 {
420 	struct sysctl_oid *oidp;
421 
422 	if (oid->oid_parent == parent)
423 		return (0);
424 	oidp = sysctl_find_oidname(oid->oid_name, parent);
425 	if (oidp != NULL)
426 		return (EEXIST);
427 	sysctl_unregister_oid(oid);
428 	oid->oid_parent = parent;
429 	oid->oid_number = OID_AUTO;
430 	sysctl_register_oid(oid);
431 	return (0);
432 }
433 
434 /*
435  * Register the kernel's oids on startup.
436  */
437 SET_DECLARE(sysctl_set, struct sysctl_oid);
438 
439 static void
440 sysctl_register_all(void *arg)
441 {
442 	struct sysctl_oid **oidp;
443 
444 	SYSCTL_INIT();
445 	SET_FOREACH(oidp, sysctl_set)
446 		sysctl_register_oid(*oidp);
447 }
448 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
449 
450 /*
451  * "Staff-functions"
452  *
453  * These functions implement a presently undocumented interface
454  * used by the sysctl program to walk the tree, and get the type
455  * so it can print the value.
456  * This interface is under work and consideration, and should probably
457  * be killed with a big axe by the first person who can find the time.
458  * (be aware though, that the proper interface isn't as obvious as it
459  * may seem, there are various conflicting requirements.
460  *
461  * {0,0}	printf the entire MIB-tree.
462  * {0,1,...}	return the name of the "..." OID.
463  * {0,2,...}	return the next OID.
464  * {0,3}	return the OID of the name in "new"
465  * {0,4,...}	return the kind & format info for the "..." OID.
466  * {0,5,...}	return the description the "..." OID.
467  */
468 
469 static void
470 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
471 {
472 	int k;
473 	struct sysctl_oid *oidp;
474 
475 	SLIST_FOREACH(oidp, l, oid_link) {
476 
477 		for (k=0; k<i; k++)
478 			printf(" ");
479 
480 		printf("%d %s ", oidp->oid_number, oidp->oid_name);
481 
482 		printf("%c%c",
483 			oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
484 			oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
485 
486 		if (oidp->oid_handler)
487 			printf(" *Handler");
488 
489 		switch (oidp->oid_kind & CTLTYPE) {
490 			case CTLTYPE_NODE:
491 				printf(" Node\n");
492 				if (!oidp->oid_handler) {
493 					sysctl_sysctl_debug_dump_node(
494 						oidp->oid_arg1, i+2);
495 				}
496 				break;
497 			case CTLTYPE_INT:    printf(" Int\n"); break;
498 			case CTLTYPE_STRING: printf(" String\n"); break;
499 			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
500 			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
501 			default:	     printf("\n");
502 		}
503 
504 	}
505 }
506 
507 static int
508 sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
509 {
510 	int error;
511 
512 	error = suser(req->td);
513 	if (error)
514 		return error;
515 	sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
516 	return ENOENT;
517 }
518 
519 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
520 	0, 0, sysctl_sysctl_debug, "-", "");
521 
522 static int
523 sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
524 {
525 	int *name = (int *) arg1;
526 	u_int namelen = arg2;
527 	int error = 0;
528 	struct sysctl_oid *oid;
529 	struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
530 	char buf[10];
531 
532 	while (namelen) {
533 		if (!lsp) {
534 			snprintf(buf,sizeof(buf),"%d",*name);
535 			if (req->oldidx)
536 				error = SYSCTL_OUT(req, ".", 1);
537 			if (!error)
538 				error = SYSCTL_OUT(req, buf, strlen(buf));
539 			if (error)
540 				return (error);
541 			namelen--;
542 			name++;
543 			continue;
544 		}
545 		lsp2 = 0;
546 		SLIST_FOREACH(oid, lsp, oid_link) {
547 			if (oid->oid_number != *name)
548 				continue;
549 
550 			if (req->oldidx)
551 				error = SYSCTL_OUT(req, ".", 1);
552 			if (!error)
553 				error = SYSCTL_OUT(req, oid->oid_name,
554 					strlen(oid->oid_name));
555 			if (error)
556 				return (error);
557 
558 			namelen--;
559 			name++;
560 
561 			if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
562 				break;
563 
564 			if (oid->oid_handler)
565 				break;
566 
567 			lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
568 			break;
569 		}
570 		lsp = lsp2;
571 	}
572 	return (SYSCTL_OUT(req, "", 1));
573 }
574 
575 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
576 
577 static int
578 sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
579 	int *next, int *len, int level, struct sysctl_oid **oidpp)
580 {
581 	struct sysctl_oid *oidp;
582 
583 	*len = level;
584 	SLIST_FOREACH(oidp, lsp, oid_link) {
585 		*next = oidp->oid_number;
586 		*oidpp = oidp;
587 
588 		if (oidp->oid_kind & CTLFLAG_SKIP)
589 			continue;
590 
591 		if (!namelen) {
592 			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
593 				return 0;
594 			if (oidp->oid_handler)
595 				/* We really should call the handler here...*/
596 				return 0;
597 			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
598 			if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
599 				len, level+1, oidpp))
600 				return 0;
601 			goto emptynode;
602 		}
603 
604 		if (oidp->oid_number < *name)
605 			continue;
606 
607 		if (oidp->oid_number > *name) {
608 			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
609 				return 0;
610 			if (oidp->oid_handler)
611 				return 0;
612 			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
613 			if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
614 				next+1, len, level+1, oidpp))
615 				return (0);
616 			goto next;
617 		}
618 		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
619 			continue;
620 
621 		if (oidp->oid_handler)
622 			continue;
623 
624 		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
625 		if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
626 			len, level+1, oidpp))
627 			return (0);
628 	next:
629 		namelen = 1;
630 	emptynode:
631 		*len = level;
632 	}
633 	return 1;
634 }
635 
636 static int
637 sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
638 {
639 	int *name = (int *) arg1;
640 	u_int namelen = arg2;
641 	int i, j, error;
642 	struct sysctl_oid *oid;
643 	struct sysctl_oid_list *lsp = &sysctl__children;
644 	int newoid[CTL_MAXNAME];
645 
646 	i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
647 	if (i)
648 		return ENOENT;
649 	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
650 	return (error);
651 }
652 
653 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
654 
655 static int
656 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
657 {
658 	int i;
659 	struct sysctl_oid *oidp;
660 	struct sysctl_oid_list *lsp = &sysctl__children;
661 	char *p;
662 
663 	if (!*name)
664 		return ENOENT;
665 
666 	p = name + strlen(name) - 1 ;
667 	if (*p == '.')
668 		*p = '\0';
669 
670 	*len = 0;
671 
672 	for (p = name; *p && *p != '.'; p++)
673 		;
674 	i = *p;
675 	if (i == '.')
676 		*p = '\0';
677 
678 	oidp = SLIST_FIRST(lsp);
679 
680 	while (oidp && *len < CTL_MAXNAME) {
681 		if (strcmp(name, oidp->oid_name)) {
682 			oidp = SLIST_NEXT(oidp, oid_link);
683 			continue;
684 		}
685 		*oid++ = oidp->oid_number;
686 		(*len)++;
687 
688 		if (!i) {
689 			if (oidpp)
690 				*oidpp = oidp;
691 			return (0);
692 		}
693 
694 		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
695 			break;
696 
697 		if (oidp->oid_handler)
698 			break;
699 
700 		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
701 		oidp = SLIST_FIRST(lsp);
702 		name = p+1;
703 		for (p = name; *p && *p != '.'; p++)
704 				;
705 		i = *p;
706 		if (i == '.')
707 			*p = '\0';
708 	}
709 	return ENOENT;
710 }
711 
712 static int
713 sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
714 {
715 	char *p;
716 	int error, oid[CTL_MAXNAME], len;
717 	struct sysctl_oid *op = 0;
718 
719 	if (!req->newlen)
720 		return ENOENT;
721 	if (req->newlen >= MAXPATHLEN)	/* XXX arbitrary, undocumented */
722 		return (ENAMETOOLONG);
723 
724 	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
725 
726 	error = SYSCTL_IN(req, p, req->newlen);
727 	if (error) {
728 		free(p, M_SYSCTL);
729 		return (error);
730 	}
731 
732 	p [req->newlen] = '\0';
733 
734 	error = name2oid(p, oid, &len, &op);
735 
736 	free(p, M_SYSCTL);
737 
738 	if (error)
739 		return (error);
740 
741 	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
742 	return (error);
743 }
744 
745 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
746 	sysctl_sysctl_name2oid, "I", "");
747 
748 static int
749 sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
750 {
751 	struct sysctl_oid *oid;
752 	int error;
753 
754 	error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
755 	if (error)
756 		return (error);
757 
758 	if (!oid->oid_fmt)
759 		return (ENOENT);
760 	error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
761 	if (error)
762 		return (error);
763 	error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
764 	return (error);
765 }
766 
767 
768 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
769 
770 static int
771 sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
772 {
773 	struct sysctl_oid *oid;
774 	int error;
775 
776 	error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
777 	if (error)
778 		return (error);
779 
780 	if (!oid->descr)
781 		return (ENOENT);
782 	error = SYSCTL_OUT(req, oid->descr, strlen(oid->descr) + 1);
783 	return (error);
784 }
785 
786 SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
787 
788 /*
789  * Default "handler" functions.
790  */
791 
792 /*
793  * Handle an int, signed or unsigned.
794  * Two cases:
795  *     a variable:  point arg1 at it.
796  *     a constant:  pass it in arg2.
797  */
798 
799 int
800 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
801 {
802 	int tmpout, error = 0;
803 
804 	/*
805 	 * Attempt to get a coherent snapshot by making a copy of the data.
806 	 */
807 	if (arg1)
808 		tmpout = *(int *)arg1;
809 	else
810 		tmpout = arg2;
811 	error = SYSCTL_OUT(req, &tmpout, sizeof(int));
812 
813 	if (error || !req->newptr)
814 		return (error);
815 
816 	if (!arg1)
817 		error = EPERM;
818 	else
819 		error = SYSCTL_IN(req, arg1, sizeof(int));
820 	return (error);
821 }
822 
823 /*
824  * Handle a long, signed or unsigned.  arg1 points to it.
825  */
826 
827 int
828 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
829 {
830 	int error = 0;
831 	long tmpout;
832 
833 	/*
834 	 * Attempt to get a coherent snapshot by making a copy of the data.
835 	 */
836 	if (!arg1)
837 		return (EINVAL);
838 	tmpout = *(long *)arg1;
839 	error = SYSCTL_OUT(req, &tmpout, sizeof(long));
840 
841 	if (error || !req->newptr)
842 		return (error);
843 
844 	error = SYSCTL_IN(req, arg1, sizeof(long));
845 	return (error);
846 }
847 
848 /*
849  * Handle our generic '\0' terminated 'C' string.
850  * Two cases:
851  * 	a variable string:  point arg1 at it, arg2 is max length.
852  * 	a constant string:  point arg1 at it, arg2 is zero.
853  */
854 
855 int
856 sysctl_handle_string(SYSCTL_HANDLER_ARGS)
857 {
858 	int error=0;
859 	char *tmparg;
860 	size_t outlen;
861 
862 	/*
863 	 * Attempt to get a coherent snapshot by copying to a
864 	 * temporary kernel buffer.
865 	 */
866 retry:
867 	outlen = strlen((char *)arg1)+1;
868 	tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK);
869 
870 	if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) {
871 		free(tmparg, M_SYSCTLTMP);
872 		goto retry;
873 	}
874 
875 	error = SYSCTL_OUT(req, tmparg, outlen);
876 	free(tmparg, M_SYSCTLTMP);
877 
878 	if (error || !req->newptr)
879 		return (error);
880 
881 	if ((req->newlen - req->newidx) >= arg2) {
882 		error = EINVAL;
883 	} else {
884 		arg2 = (req->newlen - req->newidx);
885 		error = SYSCTL_IN(req, arg1, arg2);
886 		((char *)arg1)[arg2] = '\0';
887 	}
888 
889 	return (error);
890 }
891 
892 /*
893  * Handle any kind of opaque data.
894  * arg1 points to it, arg2 is the size.
895  */
896 
897 int
898 sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
899 {
900 	int error, tries;
901 	u_int generation;
902 	struct sysctl_req req2;
903 
904 	/*
905 	 * Attempt to get a coherent snapshot, by using the thread
906 	 * pre-emption counter updated from within mi_switch() to
907 	 * determine if we were pre-empted during a bcopy() or
908 	 * copyout(). Make 3 attempts at doing this before giving up.
909 	 * If we encounter an error, stop immediately.
910 	 */
911 	tries = 0;
912 	req2 = *req;
913 retry:
914 	generation = curthread->td_generation;
915 	error = SYSCTL_OUT(req, arg1, arg2);
916 	if (error)
917 		return (error);
918 	tries++;
919 	if (generation != curthread->td_generation && tries < 3) {
920 		*req = req2;
921 		goto retry;
922 	}
923 
924 	error = SYSCTL_IN(req, arg1, arg2);
925 
926 	return (error);
927 }
928 
929 /*
930  * Transfer functions to/from kernel space.
931  * XXX: rather untested at this point
932  */
933 static int
934 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
935 {
936 	size_t i = 0;
937 
938 	if (req->oldptr) {
939 		i = l;
940 		if (req->oldlen <= req->oldidx)
941 			i = 0;
942 		else
943 			if (i > req->oldlen - req->oldidx)
944 				i = req->oldlen - req->oldidx;
945 		if (i > 0)
946 			bcopy(p, (char *)req->oldptr + req->oldidx, i);
947 	}
948 	req->oldidx += l;
949 	if (req->oldptr && i != l)
950 		return (ENOMEM);
951 	return (0);
952 }
953 
954 static int
955 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
956 {
957 	if (!req->newptr)
958 		return 0;
959 	if (req->newlen - req->newidx < l)
960 		return (EINVAL);
961 	bcopy((char *)req->newptr + req->newidx, p, l);
962 	req->newidx += l;
963 	return (0);
964 }
965 
966 int
967 kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
968     size_t *oldlenp, void *new, size_t newlen, size_t *retval)
969 {
970 	int error = 0;
971 	struct sysctl_req req;
972 
973 	bzero(&req, sizeof req);
974 
975 	req.td = td;
976 
977 	if (oldlenp) {
978 		req.oldlen = *oldlenp;
979 	}
980 	req.validlen = req.oldlen;
981 
982 	if (old) {
983 		req.oldptr= old;
984 	}
985 
986 	if (new != NULL) {
987 		req.newlen = newlen;
988 		req.newptr = new;
989 	}
990 
991 	req.oldfunc = sysctl_old_kernel;
992 	req.newfunc = sysctl_new_kernel;
993 	req.lock = REQ_LOCKED;
994 
995 	SYSCTL_LOCK();
996 
997 	error = sysctl_root(0, name, namelen, &req);
998 
999 	if (req.lock == REQ_WIRED && req.validlen > 0)
1000 		vsunlock(req.oldptr, req.validlen);
1001 
1002 	SYSCTL_UNLOCK();
1003 
1004 	if (error && error != ENOMEM)
1005 		return (error);
1006 
1007 	if (retval) {
1008 		if (req.oldptr && req.oldidx > req.validlen)
1009 			*retval = req.validlen;
1010 		else
1011 			*retval = req.oldidx;
1012 	}
1013 	return (error);
1014 }
1015 
1016 int
1017 kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
1018     void *new, size_t newlen, size_t *retval)
1019 {
1020         int oid[CTL_MAXNAME];
1021         size_t oidlen, plen;
1022 	int error;
1023 
1024 	oid[0] = 0;		/* sysctl internal magic */
1025 	oid[1] = 3;		/* name2oid */
1026 	oidlen = sizeof(oid);
1027 
1028 	error = kernel_sysctl(td, oid, 2, oid, &oidlen,
1029 	    (void *)name, strlen(name), &plen);
1030 	if (error)
1031 		return (error);
1032 
1033 	error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp,
1034 	    new, newlen, retval);
1035 	return (error);
1036 }
1037 
1038 /*
1039  * Transfer function to/from user space.
1040  */
1041 static int
1042 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1043 {
1044 	int error = 0;
1045 	size_t i, len, origidx;
1046 
1047 	origidx = req->oldidx;
1048 	req->oldidx += l;
1049 	if (req->oldptr == NULL)
1050 		return (0);
1051 	if (req->lock == REQ_LOCKED)
1052 		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
1053 		    "sysctl_old_user()");
1054 	i = l;
1055 	len = req->validlen;
1056 	if (len <= origidx)
1057 		i = 0;
1058 	else {
1059 		if (i > len - origidx)
1060 			i = len - origidx;
1061 		error = copyout(p, (char *)req->oldptr + origidx, i);
1062 	}
1063 	if (error)
1064 		return (error);
1065 	if (i < l)
1066 		return (ENOMEM);
1067 	return (0);
1068 }
1069 
1070 static int
1071 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1072 {
1073 	int error;
1074 
1075 	if (!req->newptr)
1076 		return 0;
1077 	if (req->newlen - req->newidx < l)
1078 		return (EINVAL);
1079 	error = copyin((char *)req->newptr + req->newidx, p, l);
1080 	req->newidx += l;
1081 	return (error);
1082 }
1083 
1084 /*
1085  * Wire the user space destination buffer.  If set to a value greater than
1086  * zero, the len parameter limits the maximum amount of wired memory.
1087  *
1088  * XXX - The len parameter is currently ignored due to the lack of
1089  * a place to save it in the sysctl_req structure so that the matching
1090  * amount of memory can be unwired in the sysctl exit code.
1091  */
1092 int
1093 sysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
1094 {
1095 	int ret;
1096 	size_t wiredlen;
1097 
1098 	wiredlen = (len > 0 && len < req->oldlen) ? len : req->oldlen;
1099 	ret = 0;
1100 	if (req->lock == REQ_LOCKED && req->oldptr &&
1101 	    req->oldfunc == sysctl_old_user) {
1102 		if (wiredlen != 0) {
1103 			ret = vslock(req->oldptr, wiredlen);
1104 			if (ret != 0) {
1105 				if (ret != ENOMEM)
1106 					return (ret);
1107 				wiredlen = 0;
1108 			}
1109 		}
1110 		req->lock = REQ_WIRED;
1111 		req->validlen = wiredlen;
1112 	}
1113 	return (0);
1114 }
1115 
1116 int
1117 sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
1118     int *nindx, struct sysctl_req *req)
1119 {
1120 	struct sysctl_oid *oid;
1121 	int indx;
1122 
1123 	oid = SLIST_FIRST(&sysctl__children);
1124 	indx = 0;
1125 	while (oid && indx < CTL_MAXNAME) {
1126 		if (oid->oid_number == name[indx]) {
1127 			indx++;
1128 			if (oid->oid_kind & CTLFLAG_NOLOCK)
1129 				req->lock = REQ_UNLOCKED;
1130 			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1131 				if (oid->oid_handler != NULL ||
1132 				    indx == namelen) {
1133 					*noid = oid;
1134 					if (nindx != NULL)
1135 						*nindx = indx;
1136 					return (0);
1137 				}
1138 				oid = SLIST_FIRST(
1139 				    (struct sysctl_oid_list *)oid->oid_arg1);
1140 			} else if (indx == namelen) {
1141 				*noid = oid;
1142 				if (nindx != NULL)
1143 					*nindx = indx;
1144 				return (0);
1145 			} else {
1146 				return (ENOTDIR);
1147 			}
1148 		} else {
1149 			oid = SLIST_NEXT(oid, oid_link);
1150 		}
1151 	}
1152 	return (ENOENT);
1153 }
1154 
1155 /*
1156  * Traverse our tree, and find the right node, execute whatever it points
1157  * to, and return the resulting error code.
1158  */
1159 
1160 static int
1161 sysctl_root(SYSCTL_HANDLER_ARGS)
1162 {
1163 	struct sysctl_oid *oid;
1164 	int error, indx, lvl;
1165 
1166 	error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
1167 	if (error)
1168 		return (error);
1169 
1170 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1171 		/*
1172 		 * You can't call a sysctl when it's a node, but has
1173 		 * no handler.  Inform the user that it's a node.
1174 		 * The indx may or may not be the same as namelen.
1175 		 */
1176 		if (oid->oid_handler == NULL)
1177 			return (EISDIR);
1178 	}
1179 
1180 	/* Is this sysctl writable? */
1181 	if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
1182 		return (EPERM);
1183 
1184 	KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
1185 
1186 	/* Is this sysctl sensitive to securelevels? */
1187 	if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
1188 		lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE;
1189 		error = securelevel_gt(req->td->td_ucred, lvl);
1190 		if (error)
1191 			return (error);
1192 	}
1193 
1194 	/* Is this sysctl writable by only privileged users? */
1195 	if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) {
1196 		int flags;
1197 
1198 		if (oid->oid_kind & CTLFLAG_PRISON)
1199 			flags = SUSER_ALLOWJAIL;
1200 		else
1201 			flags = 0;
1202 		error = suser_cred(req->td->td_ucred, flags);
1203 		if (error)
1204 			return (error);
1205 	}
1206 
1207 	if (!oid->oid_handler)
1208 		return EINVAL;
1209 
1210 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1211 		arg1 = (int *)arg1 + indx;
1212 		arg2 -= indx;
1213 	} else {
1214 		arg1 = oid->oid_arg1;
1215 		arg2 = oid->oid_arg2;
1216 	}
1217 #ifdef MAC
1218 	error = mac_check_system_sysctl(req->td->td_ucred, oid, arg1, arg2,
1219 	    req);
1220 	if (error != 0)
1221 		return (error);
1222 #endif
1223 	error = oid->oid_handler(oid, arg1, arg2, req);
1224 
1225 	return (error);
1226 }
1227 
1228 #ifndef _SYS_SYSPROTO_H_
1229 struct sysctl_args {
1230 	int	*name;
1231 	u_int	namelen;
1232 	void	*old;
1233 	size_t	*oldlenp;
1234 	void	*new;
1235 	size_t	newlen;
1236 };
1237 #endif
1238 
1239 /*
1240  * MPSAFE
1241  */
1242 int
1243 __sysctl(struct thread *td, struct sysctl_args *uap)
1244 {
1245 	int error, name[CTL_MAXNAME];
1246 	size_t j;
1247 
1248 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1249 		return (EINVAL);
1250 
1251  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1252  	if (error)
1253 		return (error);
1254 
1255 	mtx_lock(&Giant);
1256 
1257 	error = userland_sysctl(td, name, uap->namelen,
1258 		uap->old, uap->oldlenp, 0,
1259 		uap->new, uap->newlen, &j);
1260 	if (error && error != ENOMEM)
1261 		goto done2;
1262 	if (uap->oldlenp) {
1263 		int i = copyout(&j, uap->oldlenp, sizeof(j));
1264 		if (i)
1265 			error = i;
1266 	}
1267 done2:
1268 	mtx_unlock(&Giant);
1269 	return (error);
1270 }
1271 
1272 /*
1273  * This is used from various compatibility syscalls too.  That's why name
1274  * must be in kernel space.
1275  */
1276 int
1277 userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
1278     size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
1279 {
1280 	int error = 0;
1281 	struct sysctl_req req;
1282 
1283 	bzero(&req, sizeof req);
1284 
1285 	req.td = td;
1286 
1287 	if (oldlenp) {
1288 		if (inkernel) {
1289 			req.oldlen = *oldlenp;
1290 		} else {
1291 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1292 			if (error)
1293 				return (error);
1294 		}
1295 	}
1296 	req.validlen = req.oldlen;
1297 
1298 	if (old) {
1299 		if (!useracc(old, req.oldlen, VM_PROT_WRITE))
1300 			return (EFAULT);
1301 		req.oldptr= old;
1302 	}
1303 
1304 	if (new != NULL) {
1305 		if (!useracc(new, req.newlen, VM_PROT_READ))
1306 			return (EFAULT);
1307 		req.newlen = newlen;
1308 		req.newptr = new;
1309 	}
1310 
1311 	req.oldfunc = sysctl_old_user;
1312 	req.newfunc = sysctl_new_user;
1313 	req.lock = REQ_LOCKED;
1314 
1315 	SYSCTL_LOCK();
1316 
1317 	do {
1318 		req.oldidx = 0;
1319 		req.newidx = 0;
1320 		error = sysctl_root(0, name, namelen, &req);
1321 	} while (error == EAGAIN);
1322 
1323 	if (req.lock == REQ_WIRED && req.validlen > 0)
1324 		vsunlock(req.oldptr, req.validlen);
1325 
1326 	SYSCTL_UNLOCK();
1327 
1328 	if (error && error != ENOMEM)
1329 		return (error);
1330 
1331 	if (retval) {
1332 		if (req.oldptr && req.oldidx > req.validlen)
1333 			*retval = req.validlen;
1334 		else
1335 			*retval = req.oldidx;
1336 	}
1337 	return (error);
1338 }
1339 
1340 #ifdef COMPAT_43
1341 #include <sys/socket.h>
1342 #include <vm/vm_param.h>
1343 
1344 #define	KINFO_PROC		(0<<8)
1345 #define	KINFO_RT		(1<<8)
1346 #define	KINFO_VNODE		(2<<8)
1347 #define	KINFO_FILE		(3<<8)
1348 #define	KINFO_METER		(4<<8)
1349 #define	KINFO_LOADAVG		(5<<8)
1350 #define	KINFO_CLOCKRATE		(6<<8)
1351 
1352 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1353 #define	KINFO_BSDI_SYSINFO	(101<<8)
1354 
1355 /*
1356  * XXX this is bloat, but I hope it's better here than on the potentially
1357  * limited kernel stack...  -Peter
1358  */
1359 
1360 static struct {
1361 	int	bsdi_machine;		/* "i386" on BSD/386 */
1362 /*      ^^^ this is an offset to the string, relative to the struct start */
1363 	char	*pad0;
1364 	long	pad1;
1365 	long	pad2;
1366 	long	pad3;
1367 	u_long	pad4;
1368 	u_long	pad5;
1369 	u_long	pad6;
1370 
1371 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
1372 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
1373 	long	pad7;
1374 	long	pad8;
1375 	char	*pad9;
1376 
1377 	long	pad10;
1378 	long	pad11;
1379 	int	pad12;
1380 	long	pad13;
1381 	quad_t	pad14;
1382 	long	pad15;
1383 
1384 	struct	timeval pad16;
1385 	/* we dont set this, because BSDI's uname used gethostname() instead */
1386 	int	bsdi_hostname;		/* hostname on BSD/386 */
1387 
1388 	/* the actual string data is appended here */
1389 
1390 } bsdi_si;
1391 /*
1392  * this data is appended to the end of the bsdi_si structure during copyout.
1393  * The "char *" offsets are relative to the base of the bsdi_si struct.
1394  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1395  * should not exceed the length of the buffer here... (or else!! :-)
1396  */
1397 static char bsdi_strings[80];	/* It had better be less than this! */
1398 
1399 #ifndef _SYS_SYSPROTO_H_
1400 struct getkerninfo_args {
1401 	int	op;
1402 	char	*where;
1403 	size_t	*size;
1404 	int	arg;
1405 };
1406 #endif
1407 
1408 /*
1409  * MPSAFE
1410  */
1411 int
1412 ogetkerninfo(struct thread *td, struct getkerninfo_args *uap)
1413 {
1414 	int error, name[6];
1415 	size_t size;
1416 	u_int needed = 0;
1417 
1418 	mtx_lock(&Giant);
1419 
1420 	switch (uap->op & 0xff00) {
1421 
1422 	case KINFO_RT:
1423 		name[0] = CTL_NET;
1424 		name[1] = PF_ROUTE;
1425 		name[2] = 0;
1426 		name[3] = (uap->op & 0xff0000) >> 16;
1427 		name[4] = uap->op & 0xff;
1428 		name[5] = uap->arg;
1429 		error = userland_sysctl(td, name, 6, uap->where, uap->size,
1430 			0, 0, 0, &size);
1431 		break;
1432 
1433 	case KINFO_VNODE:
1434 		name[0] = CTL_KERN;
1435 		name[1] = KERN_VNODE;
1436 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1437 			0, 0, 0, &size);
1438 		break;
1439 
1440 	case KINFO_PROC:
1441 		name[0] = CTL_KERN;
1442 		name[1] = KERN_PROC;
1443 		name[2] = uap->op & 0xff;
1444 		name[3] = uap->arg;
1445 		error = userland_sysctl(td, name, 4, uap->where, uap->size,
1446 			0, 0, 0, &size);
1447 		break;
1448 
1449 	case KINFO_FILE:
1450 		name[0] = CTL_KERN;
1451 		name[1] = KERN_FILE;
1452 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1453 			0, 0, 0, &size);
1454 		break;
1455 
1456 	case KINFO_METER:
1457 		name[0] = CTL_VM;
1458 		name[1] = VM_TOTAL;
1459 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1460 			0, 0, 0, &size);
1461 		break;
1462 
1463 	case KINFO_LOADAVG:
1464 		name[0] = CTL_VM;
1465 		name[1] = VM_LOADAVG;
1466 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1467 			0, 0, 0, &size);
1468 		break;
1469 
1470 	case KINFO_CLOCKRATE:
1471 		name[0] = CTL_KERN;
1472 		name[1] = KERN_CLOCKRATE;
1473 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1474 			0, 0, 0, &size);
1475 		break;
1476 
1477 	case KINFO_BSDI_SYSINFO: {
1478 		/*
1479 		 * this is pretty crude, but it's just enough for uname()
1480 		 * from BSDI's 1.x libc to work.
1481 		 *
1482 		 * *size gives the size of the buffer before the call, and
1483 		 * the amount of data copied after a successful call.
1484 		 * If successful, the return value is the amount of data
1485 		 * available, which can be larger than *size.
1486 		 *
1487 		 * BSDI's 2.x product apparently fails with ENOMEM if *size
1488 		 * is too small.
1489 		 */
1490 
1491 		u_int left;
1492 		char *s;
1493 
1494 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1495 		bzero(bsdi_strings, sizeof(bsdi_strings));
1496 
1497 		s = bsdi_strings;
1498 
1499 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1500 		strcpy(s, ostype);
1501 		s += strlen(s) + 1;
1502 
1503 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1504 		strcpy(s, osrelease);
1505 		s += strlen(s) + 1;
1506 
1507 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1508 		strcpy(s, machine);
1509 		s += strlen(s) + 1;
1510 
1511 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1512 
1513 		if ((uap->where == NULL) || (uap->size == NULL)) {
1514 			/* process is asking how much buffer to supply.. */
1515 			size = needed;
1516 			error = 0;
1517 			break;
1518 		}
1519 
1520 		if ((error = copyin(uap->size, &size, sizeof(size))) != 0)
1521 			break;
1522 
1523 		/* if too much buffer supplied, trim it down */
1524 		if (size > needed)
1525 			size = needed;
1526 
1527 		/* how much of the buffer is remaining */
1528 		left = size;
1529 
1530 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1531 			break;
1532 
1533 		/* is there any point in continuing? */
1534 		if (left > sizeof(bsdi_si)) {
1535 			left -= sizeof(bsdi_si);
1536 			error = copyout(&bsdi_strings,
1537 					uap->where + sizeof(bsdi_si), left);
1538 		}
1539 		break;
1540 	}
1541 
1542 	default:
1543 		error = EOPNOTSUPP;
1544 		break;
1545 	}
1546 	if (error == 0) {
1547 		td->td_retval[0] = needed ? needed : size;
1548 		if (uap->size) {
1549 			error = copyout(&size, uap->size, sizeof(size));
1550 		}
1551 	}
1552 	mtx_unlock(&Giant);
1553 	return (error);
1554 }
1555 #endif /* COMPAT_43 */
1556