xref: /freebsd/sys/kern/kern_sysctl.c (revision 2357939bc239bd5334a169b62313806178dd8f30)
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(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 && ret != ENOMEM)
1105 				return (ret);
1106 		}
1107 		req->lock = REQ_WIRED;
1108 		req->validlen = wiredlen;
1109 	}
1110 	return (0);
1111 }
1112 
1113 int
1114 sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
1115     int *nindx, struct sysctl_req *req)
1116 {
1117 	struct sysctl_oid *oid;
1118 	int indx;
1119 
1120 	oid = SLIST_FIRST(&sysctl__children);
1121 	indx = 0;
1122 	while (oid && indx < CTL_MAXNAME) {
1123 		if (oid->oid_number == name[indx]) {
1124 			indx++;
1125 			if (oid->oid_kind & CTLFLAG_NOLOCK)
1126 				req->lock = REQ_UNLOCKED;
1127 			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1128 				if (oid->oid_handler != NULL ||
1129 				    indx == namelen) {
1130 					*noid = oid;
1131 					if (nindx != NULL)
1132 						*nindx = indx;
1133 					return (0);
1134 				}
1135 				oid = SLIST_FIRST(
1136 				    (struct sysctl_oid_list *)oid->oid_arg1);
1137 			} else if (indx == namelen) {
1138 				*noid = oid;
1139 				if (nindx != NULL)
1140 					*nindx = indx;
1141 				return (0);
1142 			} else {
1143 				return (ENOTDIR);
1144 			}
1145 		} else {
1146 			oid = SLIST_NEXT(oid, oid_link);
1147 		}
1148 	}
1149 	return (ENOENT);
1150 }
1151 
1152 /*
1153  * Traverse our tree, and find the right node, execute whatever it points
1154  * to, and return the resulting error code.
1155  */
1156 
1157 static int
1158 sysctl_root(SYSCTL_HANDLER_ARGS)
1159 {
1160 	struct sysctl_oid *oid;
1161 	int error, indx, lvl;
1162 
1163 	error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
1164 	if (error)
1165 		return (error);
1166 
1167 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1168 		/*
1169 		 * You can't call a sysctl when it's a node, but has
1170 		 * no handler.  Inform the user that it's a node.
1171 		 * The indx may or may not be the same as namelen.
1172 		 */
1173 		if (oid->oid_handler == NULL)
1174 			return (EISDIR);
1175 	}
1176 
1177 	/* Is this sysctl writable? */
1178 	if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
1179 		return (EPERM);
1180 
1181 	KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
1182 
1183 	/* Is this sysctl sensitive to securelevels? */
1184 	if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
1185 		lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE;
1186 		error = securelevel_gt(req->td->td_ucred, lvl);
1187 		if (error)
1188 			return (error);
1189 	}
1190 
1191 	/* Is this sysctl writable by only privileged users? */
1192 	if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) {
1193 		int flags;
1194 
1195 		if (oid->oid_kind & CTLFLAG_PRISON)
1196 			flags = PRISON_ROOT;
1197 		else
1198 			flags = 0;
1199 		error = suser_cred(req->td->td_ucred, flags);
1200 		if (error)
1201 			return (error);
1202 	}
1203 
1204 	if (!oid->oid_handler)
1205 		return EINVAL;
1206 
1207 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1208 		(int *)arg1 += indx;
1209 		arg2 -= indx;
1210 	} else {
1211 		arg1 = oid->oid_arg1;
1212 		arg2 = oid->oid_arg2;
1213 	}
1214 #ifdef MAC
1215 	error = mac_check_system_sysctl(req->td->td_ucred, oid, arg1, arg2,
1216 	    req);
1217 	if (error != 0)
1218 		return (error);
1219 #endif
1220 	error = oid->oid_handler(oid, arg1, arg2, req);
1221 
1222 	return (error);
1223 }
1224 
1225 #ifndef _SYS_SYSPROTO_H_
1226 struct sysctl_args {
1227 	int	*name;
1228 	u_int	namelen;
1229 	void	*old;
1230 	size_t	*oldlenp;
1231 	void	*new;
1232 	size_t	newlen;
1233 };
1234 #endif
1235 
1236 /*
1237  * MPSAFE
1238  */
1239 int
1240 __sysctl(struct thread *td, struct sysctl_args *uap)
1241 {
1242 	int error, name[CTL_MAXNAME];
1243 	size_t j;
1244 
1245 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1246 		return (EINVAL);
1247 
1248  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1249  	if (error)
1250 		return (error);
1251 
1252 	mtx_lock(&Giant);
1253 
1254 	error = userland_sysctl(td, name, uap->namelen,
1255 		uap->old, uap->oldlenp, 0,
1256 		uap->new, uap->newlen, &j);
1257 	if (error && error != ENOMEM)
1258 		goto done2;
1259 	if (uap->oldlenp) {
1260 		int i = copyout(&j, uap->oldlenp, sizeof(j));
1261 		if (i)
1262 			error = i;
1263 	}
1264 done2:
1265 	mtx_unlock(&Giant);
1266 	return (error);
1267 }
1268 
1269 /*
1270  * This is used from various compatibility syscalls too.  That's why name
1271  * must be in kernel space.
1272  */
1273 int
1274 userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
1275     size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
1276 {
1277 	int error = 0;
1278 	struct sysctl_req req;
1279 
1280 	bzero(&req, sizeof req);
1281 
1282 	req.td = td;
1283 
1284 	if (oldlenp) {
1285 		if (inkernel) {
1286 			req.oldlen = *oldlenp;
1287 		} else {
1288 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1289 			if (error)
1290 				return (error);
1291 		}
1292 	}
1293 	req.validlen = req.oldlen;
1294 
1295 	if (old) {
1296 		if (!useracc(old, req.oldlen, VM_PROT_WRITE))
1297 			return (EFAULT);
1298 		req.oldptr= old;
1299 	}
1300 
1301 	if (new != NULL) {
1302 		if (!useracc(new, req.newlen, VM_PROT_READ))
1303 			return (EFAULT);
1304 		req.newlen = newlen;
1305 		req.newptr = new;
1306 	}
1307 
1308 	req.oldfunc = sysctl_old_user;
1309 	req.newfunc = sysctl_new_user;
1310 	req.lock = REQ_LOCKED;
1311 
1312 	SYSCTL_LOCK();
1313 
1314 	do {
1315 		req.oldidx = 0;
1316 		req.newidx = 0;
1317 		error = sysctl_root(0, name, namelen, &req);
1318 	} while (error == EAGAIN);
1319 
1320 	if (req.lock == REQ_WIRED && req.validlen > 0)
1321 		vsunlock(req.oldptr, req.validlen);
1322 
1323 	SYSCTL_UNLOCK();
1324 
1325 	if (error && error != ENOMEM)
1326 		return (error);
1327 
1328 	if (retval) {
1329 		if (req.oldptr && req.oldidx > req.validlen)
1330 			*retval = req.validlen;
1331 		else
1332 			*retval = req.oldidx;
1333 	}
1334 	return (error);
1335 }
1336 
1337 #ifdef COMPAT_43
1338 #include <sys/socket.h>
1339 #include <vm/vm_param.h>
1340 
1341 #define	KINFO_PROC		(0<<8)
1342 #define	KINFO_RT		(1<<8)
1343 #define	KINFO_VNODE		(2<<8)
1344 #define	KINFO_FILE		(3<<8)
1345 #define	KINFO_METER		(4<<8)
1346 #define	KINFO_LOADAVG		(5<<8)
1347 #define	KINFO_CLOCKRATE		(6<<8)
1348 
1349 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1350 #define	KINFO_BSDI_SYSINFO	(101<<8)
1351 
1352 /*
1353  * XXX this is bloat, but I hope it's better here than on the potentially
1354  * limited kernel stack...  -Peter
1355  */
1356 
1357 static struct {
1358 	int	bsdi_machine;		/* "i386" on BSD/386 */
1359 /*      ^^^ this is an offset to the string, relative to the struct start */
1360 	char	*pad0;
1361 	long	pad1;
1362 	long	pad2;
1363 	long	pad3;
1364 	u_long	pad4;
1365 	u_long	pad5;
1366 	u_long	pad6;
1367 
1368 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
1369 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
1370 	long	pad7;
1371 	long	pad8;
1372 	char	*pad9;
1373 
1374 	long	pad10;
1375 	long	pad11;
1376 	int	pad12;
1377 	long	pad13;
1378 	quad_t	pad14;
1379 	long	pad15;
1380 
1381 	struct	timeval pad16;
1382 	/* we dont set this, because BSDI's uname used gethostname() instead */
1383 	int	bsdi_hostname;		/* hostname on BSD/386 */
1384 
1385 	/* the actual string data is appended here */
1386 
1387 } bsdi_si;
1388 /*
1389  * this data is appended to the end of the bsdi_si structure during copyout.
1390  * The "char *" offsets are relative to the base of the bsdi_si struct.
1391  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1392  * should not exceed the length of the buffer here... (or else!! :-)
1393  */
1394 static char bsdi_strings[80];	/* It had better be less than this! */
1395 
1396 #ifndef _SYS_SYSPROTO_H_
1397 struct getkerninfo_args {
1398 	int	op;
1399 	char	*where;
1400 	size_t	*size;
1401 	int	arg;
1402 };
1403 #endif
1404 
1405 /*
1406  * MPSAFE
1407  */
1408 int
1409 ogetkerninfo(struct thread *td, struct getkerninfo_args *uap)
1410 {
1411 	int error, name[6];
1412 	size_t size;
1413 	u_int needed = 0;
1414 
1415 	mtx_lock(&Giant);
1416 
1417 	switch (uap->op & 0xff00) {
1418 
1419 	case KINFO_RT:
1420 		name[0] = CTL_NET;
1421 		name[1] = PF_ROUTE;
1422 		name[2] = 0;
1423 		name[3] = (uap->op & 0xff0000) >> 16;
1424 		name[4] = uap->op & 0xff;
1425 		name[5] = uap->arg;
1426 		error = userland_sysctl(td, name, 6, uap->where, uap->size,
1427 			0, 0, 0, &size);
1428 		break;
1429 
1430 	case KINFO_VNODE:
1431 		name[0] = CTL_KERN;
1432 		name[1] = KERN_VNODE;
1433 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1434 			0, 0, 0, &size);
1435 		break;
1436 
1437 	case KINFO_PROC:
1438 		name[0] = CTL_KERN;
1439 		name[1] = KERN_PROC;
1440 		name[2] = uap->op & 0xff;
1441 		name[3] = uap->arg;
1442 		error = userland_sysctl(td, name, 4, uap->where, uap->size,
1443 			0, 0, 0, &size);
1444 		break;
1445 
1446 	case KINFO_FILE:
1447 		name[0] = CTL_KERN;
1448 		name[1] = KERN_FILE;
1449 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1450 			0, 0, 0, &size);
1451 		break;
1452 
1453 	case KINFO_METER:
1454 		name[0] = CTL_VM;
1455 		name[1] = VM_TOTAL;
1456 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1457 			0, 0, 0, &size);
1458 		break;
1459 
1460 	case KINFO_LOADAVG:
1461 		name[0] = CTL_VM;
1462 		name[1] = VM_LOADAVG;
1463 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1464 			0, 0, 0, &size);
1465 		break;
1466 
1467 	case KINFO_CLOCKRATE:
1468 		name[0] = CTL_KERN;
1469 		name[1] = KERN_CLOCKRATE;
1470 		error = userland_sysctl(td, name, 2, uap->where, uap->size,
1471 			0, 0, 0, &size);
1472 		break;
1473 
1474 	case KINFO_BSDI_SYSINFO: {
1475 		/*
1476 		 * this is pretty crude, but it's just enough for uname()
1477 		 * from BSDI's 1.x libc to work.
1478 		 *
1479 		 * *size gives the size of the buffer before the call, and
1480 		 * the amount of data copied after a successful call.
1481 		 * If successful, the return value is the amount of data
1482 		 * available, which can be larger than *size.
1483 		 *
1484 		 * BSDI's 2.x product apparently fails with ENOMEM if *size
1485 		 * is too small.
1486 		 */
1487 
1488 		u_int left;
1489 		char *s;
1490 
1491 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1492 		bzero(bsdi_strings, sizeof(bsdi_strings));
1493 
1494 		s = bsdi_strings;
1495 
1496 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1497 		strcpy(s, ostype);
1498 		s += strlen(s) + 1;
1499 
1500 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1501 		strcpy(s, osrelease);
1502 		s += strlen(s) + 1;
1503 
1504 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1505 		strcpy(s, machine);
1506 		s += strlen(s) + 1;
1507 
1508 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1509 
1510 		if ((uap->where == NULL) || (uap->size == NULL)) {
1511 			/* process is asking how much buffer to supply.. */
1512 			size = needed;
1513 			error = 0;
1514 			break;
1515 		}
1516 
1517 		if ((error = copyin(uap->size, &size, sizeof(size))) != 0)
1518 			break;
1519 
1520 		/* if too much buffer supplied, trim it down */
1521 		if (size > needed)
1522 			size = needed;
1523 
1524 		/* how much of the buffer is remaining */
1525 		left = size;
1526 
1527 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1528 			break;
1529 
1530 		/* is there any point in continuing? */
1531 		if (left > sizeof(bsdi_si)) {
1532 			left -= sizeof(bsdi_si);
1533 			error = copyout(&bsdi_strings,
1534 					uap->where + sizeof(bsdi_si), left);
1535 		}
1536 		break;
1537 	}
1538 
1539 	default:
1540 		error = EOPNOTSUPP;
1541 		break;
1542 	}
1543 	if (error == 0) {
1544 		td->td_retval[0] = needed ? needed : size;
1545 		if (uap->size) {
1546 			error = copyout(&size, uap->size, sizeof(size));
1547 		}
1548 	}
1549 	mtx_unlock(&Giant);
1550 	return (error);
1551 }
1552 #endif /* COMPAT_43 */
1553