kern_sysctl.c revision 100487
11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley by
61541Srgrimes * Mike Karels at Berkeley Software Design, Inc.
71541Srgrimes *
812623Sphk * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
912623Sphk * project, to make these variables more userfriendly.
1012623Sphk *
111541Srgrimes * Redistribution and use in source and binary forms, with or without
121541Srgrimes * modification, are permitted provided that the following conditions
131541Srgrimes * are met:
141541Srgrimes * 1. Redistributions of source code must retain the above copyright
151541Srgrimes *    notice, this list of conditions and the following disclaimer.
161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer in the
181541Srgrimes *    documentation and/or other materials provided with the distribution.
191541Srgrimes * 3. All advertising materials mentioning features or use of this software
201541Srgrimes *    must display the following acknowledgement:
211541Srgrimes *	This product includes software developed by the University of
221541Srgrimes *	California, Berkeley and its contributors.
231541Srgrimes * 4. Neither the name of the University nor the names of its contributors
241541Srgrimes *    may be used to endorse or promote products derived from this software
251541Srgrimes *    without specific prior written permission.
261541Srgrimes *
271541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
281541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
291541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
301541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
311541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
321541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
331541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
341541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
351541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
361541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
371541Srgrimes * SUCH DAMAGE.
381541Srgrimes *
391541Srgrimes *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
4050477Speter * $FreeBSD: head/sys/kern/kern_sysctl.c 100487 2002-07-22 08:25:37Z truckman $
411541Srgrimes */
421541Srgrimes
4331778Seivind#include "opt_compat.h"
4431778Seivind
451541Srgrimes#include <sys/param.h>
4648274Speter#include <sys/systm.h>
4748274Speter#include <sys/kernel.h>
481541Srgrimes#include <sys/sysctl.h>
4912623Sphk#include <sys/malloc.h>
5012662Sdg#include <sys/proc.h>
5182746Sdillon#include <sys/lock.h>
5282746Sdillon#include <sys/mutex.h>
5393616Salfred#include <sys/sx.h>
5415103Sphk#include <sys/sysproto.h>
5512645Sbde#include <vm/vm.h>
5612662Sdg#include <vm/vm_extern.h>
5712645Sbde
5830354Sphkstatic MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
5963212Sabialstatic MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
6030309Sphk
6112429Sphk/*
6293625Srwatson * Locking - this locks the sysctl tree in memory.
6312429Sphk */
6493625Srwatsonstatic struct sx sysctllock;
6512429Sphk
6693625Srwatson#define	SYSCTL_LOCK()		sx_xlock(&sysctllock)
6793625Srwatson#define	SYSCTL_UNLOCK()	sx_xunlock(&sysctllock)
6893625Srwatson#define	SYSCTL_INIT()		sx_init(&sysctllock, "sysctl sysctllock")
6993616Salfred
7062573Sphkstatic int sysctl_root(SYSCTL_HANDLER_ARGS);
7112429Sphk
7244078Sdfrstruct sysctl_oid_list sysctl__children; /* root list */
7312152Sphk
7463212Sabialstatic struct sysctl_oid *
7563212Sabialsysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
7663212Sabial{
7763212Sabial	struct sysctl_oid *oidp;
7863212Sabial
7963212Sabial	SLIST_FOREACH(oidp, list, oid_link) {
8063212Sabial		if (strcmp(oidp->oid_name, name) == 0) {
8163212Sabial			return (oidp);
8263212Sabial		}
8363212Sabial	}
8463212Sabial	return (NULL);
8563212Sabial}
8663212Sabial
8712623Sphk/*
8812623Sphk * Initialization of the MIB tree.
8912623Sphk *
9044078Sdfr * Order by number in each list.
9112623Sphk */
9212429Sphk
9380338Sroamvoid
9480338Sroamsysctl_register_oid(struct sysctl_oid *oidp)
9512152Sphk{
9644078Sdfr	struct sysctl_oid_list *parent = oidp->oid_parent;
9744078Sdfr	struct sysctl_oid *p;
9844078Sdfr	struct sysctl_oid *q;
9912197Sbde
10044078Sdfr	/*
10163212Sabial	 * First check if another oid with the same name already
10263212Sabial	 * exists in the parent's list.
10363212Sabial	 */
10463212Sabial	p = sysctl_find_oidname(oidp->oid_name, parent);
10563212Sabial	if (p != NULL) {
10663212Sabial		if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
10763212Sabial			p->oid_refcnt++;
10863212Sabial			return;
10963212Sabial		} else {
11063212Sabial			printf("can't re-use a leaf (%s)!\n", p->oid_name);
11163212Sabial			return;
11263212Sabial		}
11363212Sabial	}
11463212Sabial	/*
11544078Sdfr	 * If this oid has a number OID_AUTO, give it a number which
11680339Sroam	 * is greater than any current oid.
11780339Sroam	 * NOTE: DO NOT change the starting value here, change it in
11880339Sroam	 * <sys/sysctl.h>, and make sure it is at least 256 to
11980339Sroam	 * accomodate e.g. net.inet.raw as a static sysctl node.
12044078Sdfr	 */
12144078Sdfr	if (oidp->oid_number == OID_AUTO) {
12280339Sroam		static int newoid = CTL_AUTO_START;
12371510Smckusick
12471510Smckusick		oidp->oid_number = newoid++;
12571510Smckusick		if (newoid == 0x7fffffff)
12671510Smckusick			panic("out of oids");
12744078Sdfr	}
12884832Sroam#if 0
12984832Sroam	else if (oidp->oid_number >= CTL_AUTO_START) {
13084832Sroam		/* do not panic; this happens when unregistering sysctl sets */
13184832Sroam		printf("static sysctl oid too high: %d", oidp->oid_number);
13284832Sroam	}
13384832Sroam#endif
13444078Sdfr
13544078Sdfr	/*
13644078Sdfr	 * Insert the oid into the parent's list in order.
13744078Sdfr	 */
13844078Sdfr	q = NULL;
13944078Sdfr	SLIST_FOREACH(p, parent, oid_link) {
14044078Sdfr		if (oidp->oid_number < p->oid_number)
14144078Sdfr			break;
14244078Sdfr		q = p;
14344078Sdfr	}
14444078Sdfr	if (q)
14544078Sdfr		SLIST_INSERT_AFTER(q, oidp, oid_link);
14644078Sdfr	else
14744078Sdfr		SLIST_INSERT_HEAD(parent, oidp, oid_link);
14812152Sphk}
14912131Sphk
15080338Sroamvoid
15180338Sroamsysctl_unregister_oid(struct sysctl_oid *oidp)
15212152Sphk{
15360938Sjake	SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
15444078Sdfr}
15512152Sphk
15663212Sabial/* Initialize a new context to keep track of dynamically added sysctls. */
15763212Sabialint
15863212Sabialsysctl_ctx_init(struct sysctl_ctx_list *c)
15963212Sabial{
16063212Sabial
16163212Sabial	if (c == NULL) {
16263212Sabial		return (EINVAL);
16363212Sabial	}
16463212Sabial	TAILQ_INIT(c);
16563212Sabial	return (0);
16663212Sabial}
16763212Sabial
16863212Sabial/* Free the context, and destroy all dynamic oids registered in this context */
16963212Sabialint
17063212Sabialsysctl_ctx_free(struct sysctl_ctx_list *clist)
17163212Sabial{
17263212Sabial	struct sysctl_ctx_entry *e, *e1;
17363212Sabial	int error;
17463212Sabial
17563212Sabial	error = 0;
17663212Sabial	/*
17763212Sabial	 * First perform a "dry run" to check if it's ok to remove oids.
17863212Sabial	 * XXX FIXME
17963212Sabial	 * XXX This algorithm is a hack. But I don't know any
18063212Sabial	 * XXX better solution for now...
18163212Sabial	 */
18263212Sabial	TAILQ_FOREACH(e, clist, link) {
18363212Sabial		error = sysctl_remove_oid(e->entry, 0, 0);
18463212Sabial		if (error)
18563212Sabial			break;
18663212Sabial	}
18763212Sabial	/*
18863212Sabial	 * Restore deregistered entries, either from the end,
18963212Sabial	 * or from the place where error occured.
19063212Sabial	 * e contains the entry that was not unregistered
19163212Sabial	 */
19263212Sabial	if (error)
19363212Sabial		e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
19463212Sabial	else
19563212Sabial		e1 = TAILQ_LAST(clist, sysctl_ctx_list);
19663212Sabial	while (e1 != NULL) {
19763212Sabial		sysctl_register_oid(e1->entry);
19863212Sabial		e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
19963212Sabial	}
20063212Sabial	if (error)
20163212Sabial		return(EBUSY);
20263212Sabial	/* Now really delete the entries */
20363212Sabial	e = TAILQ_FIRST(clist);
20463212Sabial	while (e != NULL) {
20563212Sabial		e1 = TAILQ_NEXT(e, link);
20663212Sabial		error = sysctl_remove_oid(e->entry, 1, 0);
20763212Sabial		if (error)
20863212Sabial			panic("sysctl_remove_oid: corrupt tree, entry: %s",
20963212Sabial			    e->entry->oid_name);
21063212Sabial		free(e, M_SYSCTLOID);
21163212Sabial		e = e1;
21263212Sabial	}
21363212Sabial	return (error);
21463212Sabial}
21563212Sabial
21663212Sabial/* Add an entry to the context */
21763212Sabialstruct sysctl_ctx_entry *
21863212Sabialsysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
21963212Sabial{
22063212Sabial	struct sysctl_ctx_entry *e;
22163212Sabial
22263212Sabial	if (clist == NULL || oidp == NULL)
22363212Sabial		return(NULL);
22463978Speter	e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
22563212Sabial	e->entry = oidp;
22663212Sabial	TAILQ_INSERT_HEAD(clist, e, link);
22763212Sabial	return (e);
22863212Sabial}
22963212Sabial
23063212Sabial/* Find an entry in the context */
23163212Sabialstruct sysctl_ctx_entry *
23263212Sabialsysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
23363212Sabial{
23463212Sabial	struct sysctl_ctx_entry *e;
23563212Sabial
23663212Sabial	if (clist == NULL || oidp == NULL)
23763212Sabial		return(NULL);
23871999Sphk	TAILQ_FOREACH(e, clist, link) {
23963212Sabial		if(e->entry == oidp)
24063212Sabial			return(e);
24163212Sabial	}
24263212Sabial	return (e);
24363212Sabial}
24463212Sabial
24544078Sdfr/*
24663212Sabial * Delete an entry from the context.
24763212Sabial * NOTE: this function doesn't free oidp! You have to remove it
24863212Sabial * with sysctl_remove_oid().
24963212Sabial */
25063212Sabialint
25163212Sabialsysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
25263212Sabial{
25363212Sabial	struct sysctl_ctx_entry *e;
25463212Sabial
25563212Sabial	if (clist == NULL || oidp == NULL)
25663212Sabial		return (EINVAL);
25763212Sabial	e = sysctl_ctx_entry_find(clist, oidp);
25863212Sabial	if (e != NULL) {
25963212Sabial		TAILQ_REMOVE(clist, e, link);
26063212Sabial		free(e, M_SYSCTLOID);
26163212Sabial		return (0);
26263212Sabial	} else
26363212Sabial		return (ENOENT);
26463212Sabial}
26563212Sabial
26663212Sabial/*
26763212Sabial * Remove dynamically created sysctl trees.
26863212Sabial * oidp - top of the tree to be removed
26963212Sabial * del - if 0 - just deregister, otherwise free up entries as well
27063212Sabial * recurse - if != 0 traverse the subtree to be deleted
27163212Sabial */
27263212Sabialint
27363212Sabialsysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
27463212Sabial{
27563212Sabial	struct sysctl_oid *p;
27663212Sabial	int error;
27763212Sabial
27863212Sabial	if (oidp == NULL)
27963212Sabial		return(EINVAL);
28063212Sabial	if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
28163212Sabial		printf("can't remove non-dynamic nodes!\n");
28263212Sabial		return (EINVAL);
28363212Sabial	}
28463212Sabial	/*
28563212Sabial	 * WARNING: normal method to do this should be through
28663212Sabial	 * sysctl_ctx_free(). Use recursing as the last resort
28763212Sabial	 * method to purge your sysctl tree of leftovers...
28863212Sabial	 * However, if some other code still references these nodes,
28963212Sabial	 * it will panic.
29063212Sabial	 */
29163212Sabial	if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
29263212Sabial		if (oidp->oid_refcnt == 1) {
29363212Sabial			SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
29463212Sabial				if (!recurse)
29563212Sabial					return (ENOTEMPTY);
29663212Sabial				error = sysctl_remove_oid(p, del, recurse);
29763212Sabial				if (error)
29863212Sabial					return (error);
29963212Sabial			}
30063212Sabial			if (del)
30163212Sabial				free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
30263212Sabial		}
30363212Sabial	}
30463212Sabial	if (oidp->oid_refcnt > 1 ) {
30563212Sabial		oidp->oid_refcnt--;
30663212Sabial	} else {
30763212Sabial		if (oidp->oid_refcnt == 0) {
30863212Sabial			printf("Warning: bad oid_refcnt=%u (%s)!\n",
30963212Sabial				oidp->oid_refcnt, oidp->oid_name);
31063212Sabial			return (EINVAL);
31163212Sabial		}
31263212Sabial		sysctl_unregister_oid(oidp);
31363212Sabial		if (del) {
31488006Sluigi			if (oidp->descr)
315100113Smarkm				free((void *)(uintptr_t)(const void *)oidp->descr, M_SYSCTLOID);
31663978Speter			free((void *)(uintptr_t)(const void *)oidp->oid_name,
31763978Speter			     M_SYSCTLOID);
31863212Sabial			free(oidp, M_SYSCTLOID);
31963212Sabial		}
32063212Sabial	}
32163212Sabial	return (0);
32263212Sabial}
32363212Sabial
32463212Sabial/*
32563212Sabial * Create new sysctls at run time.
32663212Sabial * clist may point to a valid context initialized with sysctl_ctx_init().
32763212Sabial */
32863212Sabialstruct sysctl_oid *
32963212Sabialsysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
33070679Sjhb	int number, const char *name, int kind, void *arg1, int arg2,
33170679Sjhb	int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
33263212Sabial{
33363212Sabial	struct sysctl_oid *oidp;
33463212Sabial	ssize_t len;
33563978Speter	char *newname;
33663212Sabial
33763212Sabial	/* You have to hook up somewhere.. */
33863212Sabial	if (parent == NULL)
33963212Sabial		return(NULL);
34063212Sabial	/* Check if the node already exists, otherwise create it */
34163212Sabial	oidp = sysctl_find_oidname(name, parent);
34263212Sabial	if (oidp != NULL) {
34363212Sabial		if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
34463212Sabial			oidp->oid_refcnt++;
34563212Sabial			/* Update the context */
34663212Sabial			if (clist != NULL)
34763212Sabial				sysctl_ctx_entry_add(clist, oidp);
34863212Sabial			return (oidp);
34963212Sabial		} else {
35063212Sabial			printf("can't re-use a leaf (%s)!\n", name);
35163212Sabial			return (NULL);
35263212Sabial		}
35363212Sabial	}
35469781Sdwmalone	oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO);
35563212Sabial	oidp->oid_parent = parent;
35663212Sabial	SLIST_NEXT(oidp, oid_link) = NULL;
35763212Sabial	oidp->oid_number = number;
35863212Sabial	oidp->oid_refcnt = 1;
35963212Sabial	len = strlen(name);
36063978Speter	newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
36163978Speter	bcopy(name, newname, len + 1);
36263978Speter	newname[len] = '\0';
36363978Speter	oidp->oid_name = newname;
36463212Sabial	oidp->oid_handler = handler;
36563212Sabial	oidp->oid_kind = CTLFLAG_DYN | kind;
36663212Sabial	if ((kind & CTLTYPE) == CTLTYPE_NODE) {
36763212Sabial		/* Allocate space for children */
36863212Sabial		SYSCTL_CHILDREN(oidp) = malloc(sizeof(struct sysctl_oid_list),
36963212Sabial		    M_SYSCTLOID, M_WAITOK);
37063212Sabial		SLIST_INIT(SYSCTL_CHILDREN(oidp));
37163212Sabial	} else {
37263212Sabial		oidp->oid_arg1 = arg1;
37363212Sabial		oidp->oid_arg2 = arg2;
37463212Sabial	}
37563212Sabial	oidp->oid_fmt = fmt;
37688006Sluigi	if (descr) {
37788006Sluigi		int len = strlen(descr) + 1;
37888006Sluigi		oidp->descr = malloc(len, M_SYSCTLOID, M_WAITOK);
37988006Sluigi		if (oidp->descr)
380100113Smarkm			strcpy((char *)(uintptr_t)(const void *)oidp->descr, descr);
38188006Sluigi	}
38263212Sabial	/* Update the context, if used */
38363212Sabial	if (clist != NULL)
38463212Sabial		sysctl_ctx_entry_add(clist, oidp);
38563212Sabial	/* Register this oid */
38663212Sabial	sysctl_register_oid(oidp);
38763212Sabial	return (oidp);
38863212Sabial}
38963212Sabial
39063212Sabial/*
39144078Sdfr * Register the kernel's oids on startup.
39244078Sdfr */
39378161SpeterSET_DECLARE(sysctl_set, struct sysctl_oid);
39412152Sphk
39580338Sroamstatic void
39680338Sroamsysctl_register_all(void *arg)
39738869Sbde{
39878161Speter	struct sysctl_oid **oidp;
39978161Speter
40093625Srwatson	SYSCTL_INIT();
40178161Speter	SET_FOREACH(oidp, sysctl_set)
40278161Speter		sysctl_register_oid(*oidp);
40338869Sbde}
40444078SdfrSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
40544078Sdfr
40612623Sphk/*
40712623Sphk * "Staff-functions"
40812623Sphk *
40912650Sphk * These functions implement a presently undocumented interface
41012650Sphk * used by the sysctl program to walk the tree, and get the type
41112650Sphk * so it can print the value.
41212650Sphk * This interface is under work and consideration, and should probably
41312650Sphk * be killed with a big axe by the first person who can find the time.
41412650Sphk * (be aware though, that the proper interface isn't as obvious as it
41512650Sphk * may seem, there are various conflicting requirements.
41612650Sphk *
41712623Sphk * {0,0}	printf the entire MIB-tree.
41812623Sphk * {0,1,...}	return the name of the "..." OID.
41942467Sphk * {0,2,...}	return the next OID.
42012623Sphk * {0,3}	return the OID of the name in "new"
42112650Sphk * {0,4,...}	return the kind & format info for the "..." OID.
42288006Sluigi * {0,5,...}	return the description the "..." OID.
42312623Sphk */
42412623Sphk
42512152Sphkstatic void
42644078Sdfrsysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
42712152Sphk{
42844078Sdfr	int k;
42944078Sdfr	struct sysctl_oid *oidp;
43012152Sphk
43144078Sdfr	SLIST_FOREACH(oidp, l, oid_link) {
43212152Sphk
43312152Sphk		for (k=0; k<i; k++)
43412152Sphk			printf(" ");
43512152Sphk
43644078Sdfr		printf("%d %s ", oidp->oid_number, oidp->oid_name);
43712152Sphk
43812152Sphk		printf("%c%c",
43944078Sdfr			oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
44044078Sdfr			oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
44112152Sphk
44244078Sdfr		if (oidp->oid_handler)
44315241Sphk			printf(" *Handler");
44415241Sphk
44544078Sdfr		switch (oidp->oid_kind & CTLTYPE) {
44612243Sphk			case CTLTYPE_NODE:
44715241Sphk				printf(" Node\n");
44844078Sdfr				if (!oidp->oid_handler) {
44912152Sphk					sysctl_sysctl_debug_dump_node(
45044078Sdfr						oidp->oid_arg1, i+2);
45112152Sphk				}
45212152Sphk				break;
45312152Sphk			case CTLTYPE_INT:    printf(" Int\n"); break;
45412152Sphk			case CTLTYPE_STRING: printf(" String\n"); break;
45512152Sphk			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
45612152Sphk			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
45712152Sphk			default:	     printf("\n");
45812152Sphk		}
45912152Sphk
46012152Sphk	}
46112152Sphk}
46212152Sphk
46312152Sphkstatic int
46462573Sphksysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
46512152Sphk{
46687024Speter	int error;
46787024Speter
46893593Sjhb	error = suser(req->td);
46987024Speter	if (error)
47087024Speter		return error;
47144078Sdfr	sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
47212152Sphk	return ENOENT;
47312152Sphk}
47412152Sphk
47512152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
47612623Sphk	0, 0, sysctl_sysctl_debug, "-", "");
47712152Sphk
47812623Sphkstatic int
47962573Sphksysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
48012623Sphk{
48112623Sphk	int *name = (int *) arg1;
48212623Sphk	u_int namelen = arg2;
48344078Sdfr	int error = 0;
48444078Sdfr	struct sysctl_oid *oid;
48544972Sphk	struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
48612623Sphk	char buf[10];
48712131Sphk
48812623Sphk	while (namelen) {
48912623Sphk		if (!lsp) {
49041514Sarchie			snprintf(buf,sizeof(buf),"%d",*name);
49112623Sphk			if (req->oldidx)
49212623Sphk				error = SYSCTL_OUT(req, ".", 1);
49312623Sphk			if (!error)
49412623Sphk				error = SYSCTL_OUT(req, buf, strlen(buf));
49512623Sphk			if (error)
49612623Sphk				return (error);
49712623Sphk			namelen--;
49812623Sphk			name++;
49912623Sphk			continue;
50012623Sphk		}
50144972Sphk		lsp2 = 0;
50244078Sdfr		SLIST_FOREACH(oid, lsp, oid_link) {
50344078Sdfr			if (oid->oid_number != *name)
50412623Sphk				continue;
50512131Sphk
50612623Sphk			if (req->oldidx)
50712623Sphk				error = SYSCTL_OUT(req, ".", 1);
50812623Sphk			if (!error)
50944078Sdfr				error = SYSCTL_OUT(req, oid->oid_name,
51044078Sdfr					strlen(oid->oid_name));
51112623Sphk			if (error)
51212623Sphk				return (error);
51312623Sphk
51412623Sphk			namelen--;
51512623Sphk			name++;
51612623Sphk
51744972Sphk			if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
51812623Sphk				break;
51912623Sphk
52044078Sdfr			if (oid->oid_handler)
52112623Sphk				break;
52212623Sphk
52344972Sphk			lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
52412623Sphk			break;
52512623Sphk		}
52644972Sphk		lsp = lsp2;
52712623Sphk	}
52812623Sphk	return (SYSCTL_OUT(req, "", 1));
52912623Sphk}
53012623Sphk
53112623SphkSYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
53212623Sphk
53312623Sphkstatic int
53463978Spetersysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
53544078Sdfr	int *next, int *len, int level, struct sysctl_oid **oidpp)
53612623Sphk{
53744078Sdfr	struct sysctl_oid *oidp;
53812623Sphk
53912623Sphk	*len = level;
54044078Sdfr	SLIST_FOREACH(oidp, lsp, oid_link) {
54144078Sdfr		*next = oidp->oid_number;
54244078Sdfr		*oidpp = oidp;
54312623Sphk
54412623Sphk		if (!namelen) {
54544078Sdfr			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
54612623Sphk				return 0;
54744078Sdfr			if (oidp->oid_handler)
54812623Sphk				/* We really should call the handler here...*/
54912623Sphk				return 0;
55044078Sdfr			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
55163978Speter			if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
55244078Sdfr				len, level+1, oidpp))
55315241Sphk				return 0;
55415241Sphk			goto next;
55512623Sphk		}
55612623Sphk
55744078Sdfr		if (oidp->oid_number < *name)
55812623Sphk			continue;
55912623Sphk
56044078Sdfr		if (oidp->oid_number > *name) {
56144078Sdfr			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
56212623Sphk				return 0;
56344078Sdfr			if (oidp->oid_handler)
56412623Sphk				return 0;
56544078Sdfr			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
56663978Speter			if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
56744078Sdfr				next+1, len, level+1, oidpp))
56812623Sphk				return (0);
56915241Sphk			goto next;
57012623Sphk		}
57144078Sdfr		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
57212623Sphk			continue;
57312623Sphk
57444078Sdfr		if (oidp->oid_handler)
57512623Sphk			continue;
57612623Sphk
57744078Sdfr		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
57863978Speter		if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
57944078Sdfr			len, level+1, oidpp))
58012623Sphk			return (0);
58115241Sphk	next:
58212623Sphk		namelen = 1;
58312623Sphk		*len = level;
58412623Sphk	}
58512623Sphk	return 1;
58612623Sphk}
58712623Sphk
58812623Sphkstatic int
58962573Sphksysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
59012623Sphk{
59112623Sphk	int *name = (int *) arg1;
59212623Sphk	u_int namelen = arg2;
59312623Sphk	int i, j, error;
59412623Sphk	struct sysctl_oid *oid;
59544078Sdfr	struct sysctl_oid_list *lsp = &sysctl__children;
59612623Sphk	int newoid[CTL_MAXNAME];
59712623Sphk
59863978Speter	i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
59912623Sphk	if (i)
60012623Sphk		return ENOENT;
60112650Sphk	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
60212623Sphk	return (error);
60312623Sphk}
60412623Sphk
60512623SphkSYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
60612623Sphk
60712623Sphkstatic int
60844078Sdfrname2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
60912623Sphk{
61044078Sdfr	int i;
61144078Sdfr	struct sysctl_oid *oidp;
61244078Sdfr	struct sysctl_oid_list *lsp = &sysctl__children;
61312623Sphk	char *p;
61412623Sphk
61512623Sphk	if (!*name)
61612623Sphk		return ENOENT;
61712623Sphk
61812623Sphk	p = name + strlen(name) - 1 ;
61912623Sphk	if (*p == '.')
62012623Sphk		*p = '\0';
62112623Sphk
62212623Sphk	*len = 0;
62312623Sphk
62412623Sphk	for (p = name; *p && *p != '.'; p++)
62512623Sphk		;
62612623Sphk	i = *p;
62712623Sphk	if (i == '.')
62812623Sphk		*p = '\0';
62912623Sphk
63044078Sdfr	oidp = SLIST_FIRST(lsp);
63112623Sphk
63244078Sdfr	while (oidp && *len < CTL_MAXNAME) {
63344078Sdfr		if (strcmp(name, oidp->oid_name)) {
63444078Sdfr			oidp = SLIST_NEXT(oidp, oid_link);
63512623Sphk			continue;
63612623Sphk		}
63744078Sdfr		*oid++ = oidp->oid_number;
63812623Sphk		(*len)++;
63912623Sphk
64012623Sphk		if (!i) {
64144078Sdfr			if (oidpp)
64244078Sdfr				*oidpp = oidp;
64312623Sphk			return (0);
64412623Sphk		}
64512623Sphk
64644078Sdfr		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
64712623Sphk			break;
64812623Sphk
64944078Sdfr		if (oidp->oid_handler)
65012623Sphk			break;
65112623Sphk
65244078Sdfr		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
65344078Sdfr		oidp = SLIST_FIRST(lsp);
65412623Sphk		name = p+1;
65512623Sphk		for (p = name; *p && *p != '.'; p++)
65612623Sphk				;
65712623Sphk		i = *p;
65812623Sphk		if (i == '.')
65912623Sphk			*p = '\0';
66012623Sphk	}
66112623Sphk	return ENOENT;
66212623Sphk}
66312623Sphk
66412623Sphkstatic int
66562573Sphksysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
66612623Sphk{
66712623Sphk	char *p;
66812623Sphk	int error, oid[CTL_MAXNAME], len;
66912623Sphk	struct sysctl_oid *op = 0;
67012623Sphk
67112623Sphk	if (!req->newlen)
67212623Sphk		return ENOENT;
67345140Sphk	if (req->newlen >= MAXPATHLEN)	/* XXX arbitrary, undocumented */
67445140Sphk		return (ENAMETOOLONG);
67512623Sphk
67612623Sphk	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
67712623Sphk
67812623Sphk	error = SYSCTL_IN(req, p, req->newlen);
67912623Sphk	if (error) {
68012623Sphk		free(p, M_SYSCTL);
68112623Sphk		return (error);
68212623Sphk	}
68312623Sphk
68412623Sphk	p [req->newlen] = '\0';
68512623Sphk
68612623Sphk	error = name2oid(p, oid, &len, &op);
68712623Sphk
68812623Sphk	free(p, M_SYSCTL);
68912623Sphk
69012623Sphk	if (error)
69112623Sphk		return (error);
69212623Sphk
69312650Sphk	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
69412623Sphk	return (error);
69512623Sphk}
69612623Sphk
69712910SphkSYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
69812623Sphk	sysctl_sysctl_name2oid, "I", "");
69912623Sphk
70012623Sphkstatic int
70162573Sphksysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
70212623Sphk{
70344078Sdfr	struct sysctl_oid *oid;
70453977Sgreen	int error;
70512623Sphk
70653977Sgreen	error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
70753977Sgreen	if (error)
70853977Sgreen		return (error);
70912623Sphk
71044078Sdfr	if (!oid->oid_fmt)
71153977Sgreen		return (ENOENT);
71253977Sgreen	error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
71353977Sgreen	if (error)
71453977Sgreen		return (error);
71553977Sgreen	error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
71612650Sphk	return (error);
71712623Sphk}
71812623Sphk
71942467Sphk
72012623SphkSYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
72112623Sphk
72288006Sluigistatic int
72388006Sluigisysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
72488006Sluigi{
72588006Sluigi	struct sysctl_oid *oid;
72688006Sluigi	int error;
72788006Sluigi
72888006Sluigi	error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
72988006Sluigi	if (error)
73088006Sluigi		return (error);
73188006Sluigi
73288006Sluigi	if (!oid->descr)
73388006Sluigi		return (ENOENT);
73488006Sluigi	error = SYSCTL_OUT(req, oid->descr, strlen(oid->descr) + 1);
73588006Sluigi	return (error);
73688006Sluigi}
73788006Sluigi
73888006SluigiSYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
73988006Sluigi
74012243Sphk/*
74112623Sphk * Default "handler" functions.
74212623Sphk */
74312623Sphk
74412623Sphk/*
74542095Sdfr * Handle an int, signed or unsigned.
74612243Sphk * Two cases:
74712243Sphk *     a variable:  point arg1 at it.
74812243Sphk *     a constant:  pass it in arg2.
74912243Sphk */
75012243Sphk
75111865Sphkint
75262573Sphksysctl_handle_int(SYSCTL_HANDLER_ARGS)
75311863Sphk{
75412243Sphk	int error = 0;
75511863Sphk
75612243Sphk	if (arg1)
75712243Sphk		error = SYSCTL_OUT(req, arg1, sizeof(int));
75820506Sbde	else
75912243Sphk		error = SYSCTL_OUT(req, &arg2, sizeof(int));
76011863Sphk
76112243Sphk	if (error || !req->newptr)
76212243Sphk		return (error);
76311863Sphk
76412243Sphk	if (!arg1)
76512243Sphk		error = EPERM;
76612243Sphk	else
76712243Sphk		error = SYSCTL_IN(req, arg1, sizeof(int));
76812243Sphk	return (error);
76911863Sphk}
77011863Sphk
77112243Sphk/*
77245140Sphk * Handle a long, signed or unsigned.  arg1 points to it.
77338517Sdfr */
77438517Sdfr
77538517Sdfrint
77662573Sphksysctl_handle_long(SYSCTL_HANDLER_ARGS)
77738517Sdfr{
77838517Sdfr	int error = 0;
77938517Sdfr
78045140Sphk	if (!arg1)
78145140Sphk		return (EINVAL);
78242095Sdfr	error = SYSCTL_OUT(req, arg1, sizeof(long));
78338517Sdfr
78438517Sdfr	if (error || !req->newptr)
78538517Sdfr		return (error);
78638517Sdfr
78745140Sphk	error = SYSCTL_IN(req, arg1, sizeof(long));
78838517Sdfr	return (error);
78938517Sdfr}
79038517Sdfr
79138517Sdfr/*
79212243Sphk * Handle our generic '\0' terminated 'C' string.
79312243Sphk * Two cases:
79412243Sphk * 	a variable string:  point arg1 at it, arg2 is max length.
79512243Sphk * 	a constant string:  point arg1 at it, arg2 is zero.
79612243Sphk */
79712243Sphk
79811865Sphkint
79962573Sphksysctl_handle_string(SYSCTL_HANDLER_ARGS)
80011863Sphk{
80112243Sphk	int error=0;
80211863Sphk
80312297Sphk	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
80411863Sphk
80545140Sphk	if (error || !req->newptr)
80612243Sphk		return (error);
80711863Sphk
80845140Sphk	if ((req->newlen - req->newidx) >= arg2) {
80945140Sphk		error = EINVAL;
81012243Sphk	} else {
81112243Sphk		arg2 = (req->newlen - req->newidx);
81212243Sphk		error = SYSCTL_IN(req, arg1, arg2);
81312243Sphk		((char *)arg1)[arg2] = '\0';
81411863Sphk	}
81512131Sphk
81612131Sphk	return (error);
81711863Sphk}
81811863Sphk
81912243Sphk/*
82012243Sphk * Handle any kind of opaque data.
82112243Sphk * arg1 points to it, arg2 is the size.
82212243Sphk */
82312243Sphk
82411865Sphkint
82562573Sphksysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
82611863Sphk{
82712243Sphk	int error;
82812243Sphk
82912243Sphk	error = SYSCTL_OUT(req, arg1, arg2);
83012243Sphk
83112243Sphk	if (error || !req->newptr)
83212243Sphk		return (error);
83312243Sphk
83412243Sphk	error = SYSCTL_IN(req, arg1, arg2);
83512243Sphk
83612243Sphk	return (error);
83712243Sphk}
83812243Sphk
83912260Sphk/*
84012260Sphk * Transfer functions to/from kernel space.
84112260Sphk * XXX: rather untested at this point
84212260Sphk */
84312260Sphkstatic int
84438517Sdfrsysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
84512243Sphk{
84638517Sdfr	size_t i = 0;
84712260Sphk
84812260Sphk	if (req->oldptr) {
84938517Sdfr		i = l;
85073971Stmm		if (req->oldlen <= req->oldidx)
85173971Stmm			i = 0;
85273971Stmm		else
85373971Stmm			if (i > req->oldlen - req->oldidx)
85473971Stmm				i = req->oldlen - req->oldidx;
85512260Sphk		if (i > 0)
85617971Sbde			bcopy(p, (char *)req->oldptr + req->oldidx, i);
85712243Sphk	}
85812260Sphk	req->oldidx += l;
85916282Snate	if (req->oldptr && i != l)
86011863Sphk		return (ENOMEM);
86112260Sphk	return (0);
86212243Sphk}
86312243Sphk
86412260Sphkstatic int
86538517Sdfrsysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
86612243Sphk{
86712260Sphk	if (!req->newptr)
86812260Sphk		return 0;
86912260Sphk	if (req->newlen - req->newidx < l)
87011863Sphk		return (EINVAL);
87117971Sbde	bcopy((char *)req->newptr + req->newidx, p, l);
87212243Sphk	req->newidx += l;
87312131Sphk	return (0);
87411863Sphk}
87511863Sphk
87616282Snateint
87783366Sjuliankernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
87876834Sjlemon    size_t *oldlenp, void *new, size_t newlen, size_t *retval)
87916282Snate{
88016282Snate	int error = 0;
88116282Snate	struct sysctl_req req;
88216282Snate
88316282Snate	bzero(&req, sizeof req);
88416282Snate
88586183Srwatson	req.td = td;
88616282Snate
88716282Snate	if (oldlenp) {
88816282Snate		req.oldlen = *oldlenp;
88916282Snate	}
89016282Snate
89116282Snate	if (old) {
89216282Snate		req.oldptr= old;
89316282Snate	}
89416282Snate
89577646Sdd	if (new != NULL) {
89616282Snate		req.newlen = newlen;
89716282Snate		req.newptr = new;
89816282Snate	}
89916282Snate
90016282Snate	req.oldfunc = sysctl_old_kernel;
90116282Snate	req.newfunc = sysctl_new_kernel;
90216282Snate	req.lock = 1;
90316282Snate
90493625Srwatson	SYSCTL_LOCK();
90516282Snate
90616282Snate	error = sysctl_root(0, name, namelen, &req);
90716282Snate
90816282Snate	if (req.lock == 2)
90957975Sphk		vsunlock(req.oldptr, req.oldlen);
91016282Snate
91193625Srwatson	SYSCTL_UNLOCK();
91216282Snate
91316282Snate	if (error && error != ENOMEM)
91416282Snate		return (error);
91516282Snate
91616282Snate	if (retval) {
91716282Snate		if (req.oldptr && req.oldidx > req.oldlen)
91816282Snate			*retval = req.oldlen;
91916282Snate		else
92016282Snate			*retval = req.oldidx;
92116282Snate	}
92216282Snate	return (error);
92316282Snate}
92416282Snate
92576834Sjlemonint
92683366Sjuliankernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
92776834Sjlemon    void *new, size_t newlen, size_t *retval)
92876834Sjlemon{
92976834Sjlemon        int oid[CTL_MAXNAME];
93078620Smjacob        size_t oidlen, plen;
93178620Smjacob	int error;
93276834Sjlemon
93376834Sjlemon	oid[0] = 0;		/* sysctl internal magic */
93476834Sjlemon	oid[1] = 3;		/* name2oid */
93576834Sjlemon	oidlen = sizeof(oid);
93676834Sjlemon
93783366Sjulian	error = kernel_sysctl(td, oid, 2, oid, &oidlen,
93876834Sjlemon	    (void *)name, strlen(name), &plen);
93976834Sjlemon	if (error)
94076834Sjlemon		return (error);
94176834Sjlemon
94283366Sjulian	error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp,
94376834Sjlemon	    new, newlen, retval);
94476834Sjlemon	return (error);
94576834Sjlemon}
94676834Sjlemon
94712260Sphk/*
94812260Sphk * Transfer function to/from user space.
94912260Sphk */
95012260Sphkstatic int
95138517Sdfrsysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
95212243Sphk{
95338517Sdfr	int error = 0;
95438517Sdfr	size_t i = 0;
95512243Sphk
95612429Sphk	if (req->lock == 1 && req->oldptr) {
95712429Sphk		vslock(req->oldptr, req->oldlen);
95812429Sphk		req->lock = 2;
95912429Sphk	}
96012260Sphk	if (req->oldptr) {
96138517Sdfr		i = l;
96273971Stmm		if (req->oldlen <= req->oldidx)
96373971Stmm			i = 0;
96473971Stmm		else
96573971Stmm			if (i > req->oldlen - req->oldidx)
96673971Stmm				i = req->oldlen - req->oldidx;
96712260Sphk		if (i > 0)
96817971Sbde			error = copyout(p, (char *)req->oldptr + req->oldidx,
96917971Sbde					i);
97012260Sphk	}
97112260Sphk	req->oldidx += l;
97212243Sphk	if (error)
97312243Sphk		return (error);
97412260Sphk	if (req->oldptr && i < l)
97512243Sphk		return (ENOMEM);
97612260Sphk	return (0);
97712243Sphk}
97812243Sphk
97912260Sphkstatic int
98038517Sdfrsysctl_new_user(struct sysctl_req *req, void *p, size_t l)
98112243Sphk{
98212285Sphk	int error;
98312260Sphk
98412260Sphk	if (!req->newptr)
98512260Sphk		return 0;
98612260Sphk	if (req->newlen - req->newidx < l)
98712243Sphk		return (EINVAL);
98817971Sbde	error = copyin((char *)req->newptr + req->newidx, p, l);
98912243Sphk	req->newidx += l;
99012243Sphk	return (error);
99112243Sphk}
99212243Sphk
993100487Struckman/*
994100487Struckman * Wire the user space destination buffer.  If set to a value greater than
995100487Struckman * zero, the len parameter limits the maximum amount of wired memory.
996100487Struckman *
997100487Struckman * XXX - The len parameter is currently ignored due to the lack of
998100487Struckman * a place to save it in the sysctl_req structure so that the matching
999100487Struckman * amount of memory can be unwired in the sysctl exit code.
1000100487Struckman */
1001100487Struckmanvoid
1002100487Struckmansysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
1003100487Struckman{
1004100487Struckman	if (req->lock == 1 && req->oldptr && req->oldfunc == sysctl_old_user) {
1005100487Struckman		vslock(req->oldptr, req->oldlen);
1006100487Struckman		req->lock = 2;
1007100487Struckman	}
1008100487Struckman}
1009100487Struckman
10101541Srgrimesint
101153977Sgreensysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
101253977Sgreen    int *nindx, struct sysctl_req *req)
101312131Sphk{
101444078Sdfr	struct sysctl_oid *oid;
101553977Sgreen	int indx;
101612131Sphk
101753977Sgreen	oid = SLIST_FIRST(&sysctl__children);
101812131Sphk	indx = 0;
101944078Sdfr	while (oid && indx < CTL_MAXNAME) {
102044078Sdfr		if (oid->oid_number == name[indx]) {
102112131Sphk			indx++;
102244078Sdfr			if (oid->oid_kind & CTLFLAG_NOLOCK)
102312429Sphk				req->lock = 0;
102444078Sdfr			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
102553977Sgreen				if (oid->oid_handler != NULL ||
102653977Sgreen				    indx == namelen) {
102753977Sgreen					*noid = oid;
102853977Sgreen					if (nindx != NULL)
102953977Sgreen						*nindx = indx;
103053977Sgreen					return (0);
103153977Sgreen				}
103253977Sgreen				oid = SLIST_FIRST(
103353977Sgreen				    (struct sysctl_oid_list *)oid->oid_arg1);
103453977Sgreen			} else if (indx == namelen) {
103553977Sgreen				*noid = oid;
103653977Sgreen				if (nindx != NULL)
103753977Sgreen					*nindx = indx;
103853977Sgreen				return (0);
103912131Sphk			} else {
104053977Sgreen				return (ENOTDIR);
104112131Sphk			}
104212131Sphk		} else {
104344078Sdfr			oid = SLIST_NEXT(oid, oid_link);
104412131Sphk		}
104512131Sphk	}
104653977Sgreen	return (ENOENT);
104753977Sgreen}
104853977Sgreen
104953977Sgreen/*
105053977Sgreen * Traverse our tree, and find the right node, execute whatever it points
105153977Sgreen * to, and return the resulting error code.
105253977Sgreen */
105353977Sgreen
105453977Sgreenint
105562573Sphksysctl_root(SYSCTL_HANDLER_ARGS)
105653977Sgreen{
105753977Sgreen	struct sysctl_oid *oid;
105853977Sgreen	int error, indx;
105953977Sgreen
106053977Sgreen	error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
106153977Sgreen	if (error)
106253977Sgreen		return (error);
106353977Sgreen
106453977Sgreen	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
106553977Sgreen		/*
106653977Sgreen		 * You can't call a sysctl when it's a node, but has
106753977Sgreen		 * no handler.  Inform the user that it's a node.
106853977Sgreen		 * The indx may or may not be the same as namelen.
106953977Sgreen		 */
107053977Sgreen		if (oid->oid_handler == NULL)
107153977Sgreen			return (EISDIR);
107253977Sgreen	}
107353977Sgreen
107483968Srwatson	/* Is this sysctl writable? */
107583968Srwatson	if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
107612131Sphk		return (EPERM);
107712131Sphk
107892953Srwatson	KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
107992953Srwatson
108083968Srwatson	/* Is this sysctl sensitive to securelevels? */
108183968Srwatson	if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
108292953Srwatson		error = securelevel_gt(req->td->td_ucred, 0);
108392953Srwatson		if (error)
108492953Srwatson			return (error);
108583968Srwatson	}
108612910Sphk
108783968Srwatson	/* Is this sysctl writable by only privileged users? */
108883968Srwatson	if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) {
108992953Srwatson		int flags;
109083968Srwatson
109192953Srwatson		if (oid->oid_kind & CTLFLAG_PRISON)
109292953Srwatson			flags = PRISON_ROOT;
109392953Srwatson		else
109492953Srwatson			flags = 0;
109593593Sjhb		error = suser_cred(req->td->td_ucred, flags);
109692953Srwatson		if (error)
109792953Srwatson			return (error);
109883968Srwatson	}
109983968Srwatson
110044078Sdfr	if (!oid->oid_handler)
110112131Sphk		return EINVAL;
110212131Sphk
110353977Sgreen	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
110453977Sgreen		error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
110553977Sgreen		    req);
110653977Sgreen	else
110753977Sgreen		error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
110853977Sgreen		    req);
110953977Sgreen	return (error);
111012131Sphk}
111112131Sphk
111212221Sbde#ifndef _SYS_SYSPROTO_H_
111312171Sphkstruct sysctl_args {
111412171Sphk	int	*name;
111512171Sphk	u_int	namelen;
111612171Sphk	void	*old;
111712171Sphk	size_t	*oldlenp;
111812171Sphk	void	*new;
111912171Sphk	size_t	newlen;
112012171Sphk};
112112221Sbde#endif
112212171Sphk
112382746Sdillon/*
112482746Sdillon * MPSAFE
112582746Sdillon */
112612131Sphkint
112783366Sjulian__sysctl(struct thread *td, struct sysctl_args *uap)
11281541Srgrimes{
112982746Sdillon	int error, name[CTL_MAXNAME];
113038517Sdfr	size_t j;
11311541Srgrimes
11321541Srgrimes	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
11331541Srgrimes		return (EINVAL);
113411863Sphk
11353308Sphk 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
11363308Sphk 	if (error)
11371541Srgrimes		return (error);
11381541Srgrimes
113982746Sdillon	mtx_lock(&Giant);
114082746Sdillon
114183366Sjulian	error = userland_sysctl(td, name, uap->namelen,
114212171Sphk		uap->old, uap->oldlenp, 0,
114312260Sphk		uap->new, uap->newlen, &j);
114412260Sphk	if (error && error != ENOMEM)
114582746Sdillon		goto done2;
114612260Sphk	if (uap->oldlenp) {
114782746Sdillon		int i = copyout(&j, uap->oldlenp, sizeof(j));
114812260Sphk		if (i)
114982746Sdillon			error = i;
115012260Sphk	}
115182746Sdillondone2:
115282746Sdillon	mtx_unlock(&Giant);
115312260Sphk	return (error);
115412171Sphk}
115512171Sphk
115612171Sphk/*
115712171Sphk * This is used from various compatibility syscalls too.  That's why name
115812171Sphk * must be in kernel space.
115912171Sphk */
116012171Sphkint
116183366Sjulianuserland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
116280338Sroam    size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
116312171Sphk{
116412429Sphk	int error = 0;
116516159Sphk	struct sysctl_req req, req2;
116612171Sphk
116712243Sphk	bzero(&req, sizeof req);
116812243Sphk
116986183Srwatson	req.td = td;
117012285Sphk
117112171Sphk	if (oldlenp) {
117212171Sphk		if (inkernel) {
117312243Sphk			req.oldlen = *oldlenp;
117412171Sphk		} else {
117512260Sphk			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
117612171Sphk			if (error)
117712171Sphk				return (error);
117812171Sphk		}
117912171Sphk	}
118012171Sphk
118112243Sphk	if (old) {
118252644Sphk		if (!useracc(old, req.oldlen, VM_PROT_WRITE))
118312243Sphk			return (EFAULT);
118412243Sphk		req.oldptr= old;
118512243Sphk	}
118612131Sphk
118777646Sdd	if (new != NULL) {
118852644Sphk		if (!useracc(new, req.newlen, VM_PROT_READ))
118912243Sphk			return (EFAULT);
119012243Sphk		req.newlen = newlen;
119112243Sphk		req.newptr = new;
119211863Sphk	}
119312131Sphk
119412243Sphk	req.oldfunc = sysctl_old_user;
119512243Sphk	req.newfunc = sysctl_new_user;
119612429Sphk	req.lock = 1;
119711863Sphk
119893625Srwatson	SYSCTL_LOCK();
119912429Sphk
120016159Sphk	do {
120116159Sphk	    req2 = req;
120216159Sphk	    error = sysctl_root(0, name, namelen, &req2);
120316159Sphk	} while (error == EAGAIN);
120412243Sphk
120516159Sphk	req = req2;
120612429Sphk	if (req.lock == 2)
120757975Sphk		vsunlock(req.oldptr, req.oldlen);
120812429Sphk
120993625Srwatson	SYSCTL_UNLOCK();
121012429Sphk
121112260Sphk	if (error && error != ENOMEM)
121212260Sphk		return (error);
121312260Sphk
121412260Sphk	if (retval) {
121512260Sphk		if (req.oldptr && req.oldidx > req.oldlen)
121612243Sphk			*retval = req.oldlen;
121712260Sphk		else
121812260Sphk			*retval = req.oldidx;
121911863Sphk	}
122012260Sphk	return (error);
12211541Srgrimes}
12221541Srgrimes
12231541Srgrimes#ifdef COMPAT_43
12241541Srgrimes#include <sys/socket.h>
122515103Sphk#include <vm/vm_param.h>
122615103Sphk
12271541Srgrimes#define	KINFO_PROC		(0<<8)
12281541Srgrimes#define	KINFO_RT		(1<<8)
12291541Srgrimes#define	KINFO_VNODE		(2<<8)
12301541Srgrimes#define	KINFO_FILE		(3<<8)
12311541Srgrimes#define	KINFO_METER		(4<<8)
12321541Srgrimes#define	KINFO_LOADAVG		(5<<8)
12331541Srgrimes#define	KINFO_CLOCKRATE		(6<<8)
12341541Srgrimes
12359455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
12369455Speter#define	KINFO_BSDI_SYSINFO	(101<<8)
12379455Speter
12389455Speter/*
12399455Speter * XXX this is bloat, but I hope it's better here than on the potentially
12409455Speter * limited kernel stack...  -Peter
12419455Speter */
12429455Speter
124312819Sphkstatic struct {
12449455Speter	int	bsdi_machine;		/* "i386" on BSD/386 */
12459455Speter/*      ^^^ this is an offset to the string, relative to the struct start */
12469455Speter	char	*pad0;
12479455Speter	long	pad1;
12489455Speter	long	pad2;
12499455Speter	long	pad3;
12509455Speter	u_long	pad4;
12519455Speter	u_long	pad5;
12529455Speter	u_long	pad6;
12539455Speter
12549455Speter	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
12559455Speter	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
12569455Speter	long	pad7;
12579455Speter	long	pad8;
12589455Speter	char	*pad9;
12599455Speter
12609455Speter	long	pad10;
12619455Speter	long	pad11;
12629455Speter	int	pad12;
12639455Speter	long	pad13;
12649455Speter	quad_t	pad14;
12659455Speter	long	pad15;
12669455Speter
12679455Speter	struct	timeval pad16;
12689455Speter	/* we dont set this, because BSDI's uname used gethostname() instead */
12699455Speter	int	bsdi_hostname;		/* hostname on BSD/386 */
12709455Speter
12719455Speter	/* the actual string data is appended here */
12729455Speter
12739455Speter} bsdi_si;
12749455Speter/*
12759455Speter * this data is appended to the end of the bsdi_si structure during copyout.
12769455Speter * The "char *" offsets are relative to the base of the bsdi_si struct.
12779455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
12789455Speter * should not exceed the length of the buffer here... (or else!! :-)
12799455Speter */
128012819Sphkstatic char bsdi_strings[80];	/* It had better be less than this! */
12819455Speter
128212221Sbde#ifndef _SYS_SYSPROTO_H_
12831541Srgrimesstruct getkerninfo_args {
12841541Srgrimes	int	op;
12851541Srgrimes	char	*where;
128638864Sbde	size_t	*size;
12871541Srgrimes	int	arg;
12881541Srgrimes};
128912221Sbde#endif
12901541Srgrimes
129182746Sdillon/*
129282746Sdillon * MPSAFE
129382746Sdillon */
12941549Srgrimesint
129583366Sjulianogetkerninfo(struct thread *td, struct getkerninfo_args *uap)
12961541Srgrimes{
129712171Sphk	int error, name[6];
129838517Sdfr	size_t size;
129982494Speter	u_int needed = 0;
13001541Srgrimes
130182746Sdillon	mtx_lock(&Giant);
130282746Sdillon
13031541Srgrimes	switch (uap->op & 0xff00) {
13041541Srgrimes
13051541Srgrimes	case KINFO_RT:
130612171Sphk		name[0] = CTL_NET;
130712171Sphk		name[1] = PF_ROUTE;
130812171Sphk		name[2] = 0;
130912171Sphk		name[3] = (uap->op & 0xff0000) >> 16;
131012171Sphk		name[4] = uap->op & 0xff;
131112171Sphk		name[5] = uap->arg;
131283366Sjulian		error = userland_sysctl(td, name, 6, uap->where, uap->size,
131312429Sphk			0, 0, 0, &size);
13141541Srgrimes		break;
13151541Srgrimes
13161541Srgrimes	case KINFO_VNODE:
131712171Sphk		name[0] = CTL_KERN;
131812171Sphk		name[1] = KERN_VNODE;
131983366Sjulian		error = userland_sysctl(td, name, 2, uap->where, uap->size,
132012429Sphk			0, 0, 0, &size);
13211541Srgrimes		break;
13221541Srgrimes
13231541Srgrimes	case KINFO_PROC:
132412171Sphk		name[0] = CTL_KERN;
132512171Sphk		name[1] = KERN_PROC;
132612171Sphk		name[2] = uap->op & 0xff;
132712171Sphk		name[3] = uap->arg;
132883366Sjulian		error = userland_sysctl(td, name, 4, uap->where, uap->size,
132912429Sphk			0, 0, 0, &size);
13301541Srgrimes		break;
13311541Srgrimes
13321541Srgrimes	case KINFO_FILE:
133312171Sphk		name[0] = CTL_KERN;
133412171Sphk		name[1] = KERN_FILE;
133583366Sjulian		error = userland_sysctl(td, name, 2, uap->where, uap->size,
133612429Sphk			0, 0, 0, &size);
13371541Srgrimes		break;
13381541Srgrimes
13391541Srgrimes	case KINFO_METER:
134012171Sphk		name[0] = CTL_VM;
134112171Sphk		name[1] = VM_METER;
134283366Sjulian		error = userland_sysctl(td, name, 2, uap->where, uap->size,
134312429Sphk			0, 0, 0, &size);
13441541Srgrimes		break;
13451541Srgrimes
13461541Srgrimes	case KINFO_LOADAVG:
134712171Sphk		name[0] = CTL_VM;
134812171Sphk		name[1] = VM_LOADAVG;
134983366Sjulian		error = userland_sysctl(td, name, 2, uap->where, uap->size,
135012429Sphk			0, 0, 0, &size);
13511541Srgrimes		break;
13521541Srgrimes
13531541Srgrimes	case KINFO_CLOCKRATE:
135412171Sphk		name[0] = CTL_KERN;
135512171Sphk		name[1] = KERN_CLOCKRATE;
135683366Sjulian		error = userland_sysctl(td, name, 2, uap->where, uap->size,
135712429Sphk			0, 0, 0, &size);
13581541Srgrimes		break;
13591541Srgrimes
13609455Speter	case KINFO_BSDI_SYSINFO: {
13619455Speter		/*
13629455Speter		 * this is pretty crude, but it's just enough for uname()
13639455Speter		 * from BSDI's 1.x libc to work.
13649455Speter		 *
136582494Speter		 * *size gives the size of the buffer before the call, and
136682494Speter		 * the amount of data copied after a successful call.
136782494Speter		 * If successful, the return value is the amount of data
136882494Speter		 * available, which can be larger than *size.
136982494Speter		 *
137082494Speter		 * BSDI's 2.x product apparently fails with ENOMEM if *size
137182494Speter		 * is too small.
13729455Speter		 */
13739455Speter
13749455Speter		u_int left;
13759455Speter		char *s;
13769455Speter
13779455Speter		bzero((char *)&bsdi_si, sizeof(bsdi_si));
13789455Speter		bzero(bsdi_strings, sizeof(bsdi_strings));
13799455Speter
13809455Speter		s = bsdi_strings;
13819455Speter
13829455Speter		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
13839455Speter		strcpy(s, ostype);
13849455Speter		s += strlen(s) + 1;
13859455Speter
13869455Speter		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
13879455Speter		strcpy(s, osrelease);
13889455Speter		s += strlen(s) + 1;
13899455Speter
13909455Speter		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
13919455Speter		strcpy(s, machine);
13929455Speter		s += strlen(s) + 1;
13939455Speter
13949455Speter		needed = sizeof(bsdi_si) + (s - bsdi_strings);
13959455Speter
139682494Speter		if ((uap->where == NULL) || (uap->size == NULL)) {
13979455Speter			/* process is asking how much buffer to supply.. */
13989455Speter			size = needed;
13999455Speter			error = 0;
14009455Speter			break;
14019455Speter		}
14029455Speter
140382494Speter		if ((error = copyin(uap->size, &size, sizeof(size))) != 0)
140482494Speter			break;
14059455Speter
14069455Speter		/* if too much buffer supplied, trim it down */
14079455Speter		if (size > needed)
14089455Speter			size = needed;
14099455Speter
14109455Speter		/* how much of the buffer is remaining */
14119455Speter		left = size;
14129455Speter
14139455Speter		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
14149455Speter			break;
14159455Speter
14169455Speter		/* is there any point in continuing? */
14179455Speter		if (left > sizeof(bsdi_si)) {
14189455Speter			left -= sizeof(bsdi_si);
14199455Speter			error = copyout(&bsdi_strings,
14209455Speter					uap->where + sizeof(bsdi_si), left);
14219455Speter		}
14229455Speter		break;
14239455Speter	}
14249455Speter
14251541Srgrimes	default:
142682746Sdillon		error = EOPNOTSUPP;
142782746Sdillon		break;
14281541Srgrimes	}
142982746Sdillon	if (error == 0) {
143083366Sjulian		td->td_retval[0] = needed ? needed : size;
143182746Sdillon		if (uap->size) {
143299012Salfred			error = copyout(&size, uap->size, sizeof(size));
143382746Sdillon		}
143482746Sdillon	}
143582746Sdillon	mtx_unlock(&Giant);
14361541Srgrimes	return (error);
14371541Srgrimes}
14381541Srgrimes#endif /* COMPAT_43 */
1439