kern_sysctl.c revision 15103
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
4015103Sphk * $Id: kern_sysctl.c,v 1.60 1996/03/11 02:18:22 hsu Exp $
411541Srgrimes */
421541Srgrimes
431541Srgrimes#include <sys/param.h>
441541Srgrimes#include <sys/kernel.h>
451541Srgrimes#include <sys/sysctl.h>
4612623Sphk#include <sys/malloc.h>
4712662Sdg#include <sys/proc.h>
4815103Sphk#include <sys/systm.h>
4915103Sphk#include <sys/sysproto.h>
5012645Sbde#include <vm/vm.h>
5112662Sdg#include <vm/vm_extern.h>
5215103Sphk#include <sys/vnode.h>
5312645Sbde
5412429Sphk/*
5512429Sphk * Locking and stats
5612429Sphk */
5712429Sphkstatic struct sysctl_lock {
5812429Sphk	int	sl_lock;
5912429Sphk	int	sl_want;
6012429Sphk	int	sl_locked;
6112429Sphk} memlock;
6212429Sphk
6312429Sphkstatic int sysctl_root SYSCTL_HANDLER_ARGS;
6412429Sphk
6512152Sphkextern struct linker_set sysctl_;
6612152Sphk
6712623Sphk/*
6812623Sphk * Initialization of the MIB tree.
6912623Sphk *
7012623Sphk * Order by number in each linker_set.
7112623Sphk */
7212429Sphk
7312429Sphkstatic int
7412197Sbdesysctl_order_cmp(const void *a, const void *b)
7512152Sphk{
7612197Sbde	const struct sysctl_oid **pa, **pb;
7712197Sbde
7812197Sbde	pa = (const struct sysctl_oid **)a;
7912197Sbde	pb = (const struct sysctl_oid **)b;
8012197Sbde	if (*pa == NULL)
8112197Sbde		return (1);
8212197Sbde	if (*pb == NULL)
8312197Sbde		return (-1);
8412152Sphk	return ((*pa)->oid_number - (*pb)->oid_number);
8512152Sphk}
8612131Sphk
8712152Sphkstatic void
8812152Sphksysctl_order(void *arg)
8912152Sphk{
9012623Sphk	int j, k;
9112152Sphk	struct linker_set *l = (struct linker_set *) arg;
9212152Sphk	struct sysctl_oid **oidpp;
9312152Sphk
9412623Sphk	/* First, find the highest oid we have */
9512152Sphk	j = l->ls_length;
9612152Sphk	oidpp = (struct sysctl_oid **) l->ls_items;
9712623Sphk	for (k = 0; j--; oidpp++)
9812623Sphk		if (*oidpp && (*oidpp)->oid_number > k)
9912623Sphk			k = (*oidpp)->oid_number;
10012623Sphk
10112623Sphk	/* Next, replace all OID_AUTO oids with new numbers */
10212623Sphk	j = l->ls_length;
10312623Sphk	oidpp = (struct sysctl_oid **) l->ls_items;
10412623Sphk	k += 100;
10512623Sphk	for (; j--; oidpp++)
10612623Sphk		if (*oidpp && (*oidpp)->oid_number == OID_AUTO)
10712623Sphk			(*oidpp)->oid_number = k++;
10812623Sphk
10912623Sphk	/* Finally: sort by oid */
11012623Sphk	j = l->ls_length;
11112623Sphk	oidpp = (struct sysctl_oid **) l->ls_items;
11212152Sphk	for (; j--; oidpp++) {
11312152Sphk		if (!*oidpp)
11412152Sphk			continue;
11512152Sphk		if ((*oidpp)->oid_arg1 == arg) {
11612152Sphk			*oidpp = 0;
11712152Sphk			continue;
11812152Sphk		}
11912243Sphk		if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
12012152Sphk			if (!(*oidpp)->oid_handler)
12112152Sphk				sysctl_order((*oidpp)->oid_arg1);
12212152Sphk	}
12312152Sphk	qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
12412152Sphk		sysctl_order_cmp);
12512152Sphk}
12612152Sphk
12712243SphkSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
12812152Sphk
12912623Sphk/*
13012623Sphk * "Staff-functions"
13112623Sphk *
13212650Sphk * These functions implement a presently undocumented interface
13312650Sphk * used by the sysctl program to walk the tree, and get the type
13412650Sphk * so it can print the value.
13512650Sphk * This interface is under work and consideration, and should probably
13612650Sphk * be killed with a big axe by the first person who can find the time.
13712650Sphk * (be aware though, that the proper interface isn't as obvious as it
13812650Sphk * may seem, there are various conflicting requirements.
13912650Sphk *
14012623Sphk * {0,0}	printf the entire MIB-tree.
14112623Sphk * {0,1,...}	return the name of the "..." OID.
14212623Sphk * {0,2,...}	return the next OID.
14312623Sphk * {0,3}	return the OID of the name in "new"
14412650Sphk * {0,4,...}	return the kind & format info for the "..." OID.
14512623Sphk */
14612623Sphk
14712152Sphkstatic void
14812243Sphksysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
14912152Sphk{
15012243Sphk	int j, k;
15112152Sphk	struct sysctl_oid **oidpp;
15212152Sphk
15312152Sphk	j = l->ls_length;
15412152Sphk	oidpp = (struct sysctl_oid **) l->ls_items;
15512152Sphk	for (; j--; oidpp++) {
15612152Sphk
15712152Sphk		if (!*oidpp)
15812152Sphk			continue;
15912152Sphk
16012152Sphk		for (k=0; k<i; k++)
16112152Sphk			printf(" ");
16212152Sphk
16312152Sphk		if ((*oidpp)->oid_number > 100) {
16412171Sphk			printf("Junk! %p  # %d  %s  k %x  a1 %p  a2 %x  h %p\n",
16512152Sphk				*oidpp,
16612152Sphk		 		(*oidpp)->oid_number, (*oidpp)->oid_name,
16712152Sphk		 		(*oidpp)->oid_kind, (*oidpp)->oid_arg1,
16812152Sphk		 		(*oidpp)->oid_arg2, (*oidpp)->oid_handler);
16912152Sphk			continue;
17012152Sphk		}
17112152Sphk		printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
17212152Sphk
17312152Sphk		printf("%c%c",
17412152Sphk			(*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
17512152Sphk			(*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
17612152Sphk
17712152Sphk		switch ((*oidpp)->oid_kind & CTLTYPE) {
17812243Sphk			case CTLTYPE_NODE:
17912152Sphk				if ((*oidpp)->oid_handler) {
18012243Sphk					printf(" Node(proc)\n");
18112152Sphk				} else {
18212243Sphk					printf(" Node\n");
18312152Sphk					sysctl_sysctl_debug_dump_node(
18412243Sphk						(*oidpp)->oid_arg1, i+2);
18512152Sphk				}
18612152Sphk				break;
18712152Sphk			case CTLTYPE_INT:    printf(" Int\n"); break;
18812152Sphk			case CTLTYPE_STRING: printf(" String\n"); break;
18912152Sphk			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
19012152Sphk			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
19112152Sphk			default:	     printf("\n");
19212152Sphk		}
19312152Sphk
19412152Sphk	}
19512152Sphk}
19612152Sphk
19712152Sphkstatic int
19812152Sphksysctl_sysctl_debug SYSCTL_HANDLER_ARGS
19912152Sphk{
20012243Sphk	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
20112152Sphk	return ENOENT;
20212152Sphk}
20312152Sphk
20412152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
20512623Sphk	0, 0, sysctl_sysctl_debug, "-", "");
20612152Sphk
20712623Sphkstatic int
20812623Sphksysctl_sysctl_name SYSCTL_HANDLER_ARGS
20912623Sphk{
21012623Sphk	int *name = (int *) arg1;
21112623Sphk	u_int namelen = arg2;
21212623Sphk	int i, j, error = 0;
21312623Sphk	struct sysctl_oid **oidpp;
21412623Sphk	struct linker_set *lsp = &sysctl_;
21512623Sphk	char buf[10];
21612131Sphk
21712623Sphk	while (namelen) {
21812623Sphk		if (!lsp) {
21912623Sphk			sprintf(buf,"%d",*name);
22012623Sphk			if (req->oldidx)
22112623Sphk				error = SYSCTL_OUT(req, ".", 1);
22212623Sphk			if (!error)
22312623Sphk				error = SYSCTL_OUT(req, buf, strlen(buf));
22412623Sphk			if (error)
22512623Sphk				return (error);
22612623Sphk			namelen--;
22712623Sphk			name++;
22812623Sphk			continue;
22912623Sphk		}
23012623Sphk		oidpp = (struct sysctl_oid **) lsp->ls_items;
23112623Sphk		j = lsp->ls_length;
23212623Sphk		lsp = 0;
23312623Sphk		for (i = 0; i < j; i++, oidpp++) {
23412623Sphk			if (*oidpp && ((*oidpp)->oid_number != *name))
23512623Sphk				continue;
23612131Sphk
23712623Sphk			if (req->oldidx)
23812623Sphk				error = SYSCTL_OUT(req, ".", 1);
23912623Sphk			if (!error)
24012623Sphk				error = SYSCTL_OUT(req, (*oidpp)->oid_name,
24112623Sphk					strlen((*oidpp)->oid_name));
24212623Sphk			if (error)
24312623Sphk				return (error);
24412623Sphk
24512623Sphk			namelen--;
24612623Sphk			name++;
24712623Sphk
24812623Sphk			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
24912623Sphk				break;
25012623Sphk
25112623Sphk			if ((*oidpp)->oid_handler)
25212623Sphk				break;
25312623Sphk
25412623Sphk			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
25512623Sphk			break;
25612623Sphk		}
25712623Sphk	}
25812623Sphk	return (SYSCTL_OUT(req, "", 1));
25912623Sphk}
26012623Sphk
26112623SphkSYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
26212623Sphk
26312623Sphkstatic int
26412623Sphksysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen,
26512623Sphk	int *next, int *len, int level, struct sysctl_oid **oidp)
26612623Sphk{
26712623Sphk	int i, j;
26812623Sphk	struct sysctl_oid **oidpp;
26912623Sphk
27012623Sphk	oidpp = (struct sysctl_oid **) lsp->ls_items;
27112623Sphk	j = lsp->ls_length;
27212623Sphk	*len = level;
27312623Sphk	for (i = 0; i < j; i++, oidpp++) {
27412623Sphk		if (!*oidpp)
27512623Sphk			continue;
27612623Sphk
27712623Sphk		*next = (*oidpp)->oid_number;
27812623Sphk		*oidp = *oidpp;
27912623Sphk
28012623Sphk		if (!namelen) {
28112623Sphk			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
28212623Sphk				return 0;
28312623Sphk			if ((*oidpp)->oid_handler)
28412623Sphk				/* We really should call the handler here...*/
28512623Sphk				return 0;
28612623Sphk			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
28712623Sphk			return (sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
28812623Sphk				len, level+1, oidp));
28912623Sphk		}
29012623Sphk
29112623Sphk		if ((*oidpp)->oid_number < *name)
29212623Sphk			continue;
29312623Sphk
29412623Sphk		if ((*oidpp)->oid_number > *name) {
29512623Sphk			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
29612623Sphk				return 0;
29712623Sphk			if ((*oidpp)->oid_handler)
29812623Sphk				return 0;
29912623Sphk			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
30012623Sphk			if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
30112623Sphk				next+1, len, level+1, oidp))
30212623Sphk				return (0);
30312623Sphk			namelen = 1;
30412623Sphk			*len = level;
30512623Sphk			continue;
30612623Sphk		}
30712623Sphk		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
30812623Sphk			continue;
30912623Sphk
31012623Sphk		if ((*oidpp)->oid_handler)
31112623Sphk			continue;
31212623Sphk
31312623Sphk		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
31412623Sphk		if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
31512623Sphk			len, level+1, oidp))
31612623Sphk			return (0);
31712623Sphk		namelen = 1;
31812623Sphk		*len = level;
31912623Sphk	}
32012623Sphk	return 1;
32112623Sphk}
32212623Sphk
32312623Sphkstatic int
32412623Sphksysctl_sysctl_next SYSCTL_HANDLER_ARGS
32512623Sphk{
32612623Sphk	int *name = (int *) arg1;
32712623Sphk	u_int namelen = arg2;
32812623Sphk	int i, j, error;
32912623Sphk	struct sysctl_oid *oid;
33012623Sphk	struct linker_set *lsp = &sysctl_;
33112623Sphk	int newoid[CTL_MAXNAME];
33212623Sphk
33312623Sphk	i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
33412623Sphk	if (i)
33512623Sphk		return ENOENT;
33612650Sphk	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
33712623Sphk	return (error);
33812623Sphk}
33912623Sphk
34012623SphkSYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
34112623Sphk
34212623Sphkstatic int
34312623Sphkname2oid (char *name, int *oid, int *len, struct sysctl_oid **oidp)
34412623Sphk{
34512623Sphk	int i, j;
34612623Sphk	struct sysctl_oid **oidpp;
34712623Sphk	struct linker_set *lsp = &sysctl_;
34812623Sphk	char *p;
34912623Sphk
35012623Sphk	if (!*name)
35112623Sphk		return ENOENT;
35212623Sphk
35312623Sphk	p = name + strlen(name) - 1 ;
35412623Sphk	if (*p == '.')
35512623Sphk		*p = '\0';
35612623Sphk
35712623Sphk	*len = 0;
35812623Sphk
35912623Sphk	for (p = name; *p && *p != '.'; p++)
36012623Sphk		;
36112623Sphk	i = *p;
36212623Sphk	if (i == '.')
36312623Sphk		*p = '\0';
36412623Sphk
36512623Sphk	j = lsp->ls_length;
36612623Sphk	oidpp = (struct sysctl_oid **) lsp->ls_items;
36712623Sphk
36812623Sphk	while (j-- && *len < CTL_MAXNAME) {
36912623Sphk		if (!*oidpp)
37012623Sphk			continue;
37112623Sphk		if (strcmp(name, (*oidpp)->oid_name)) {
37212623Sphk			oidpp++;
37312623Sphk			continue;
37412623Sphk		}
37512623Sphk		*oid++ = (*oidpp)->oid_number;
37612623Sphk		(*len)++;
37712623Sphk
37812623Sphk		if (!i) {
37912623Sphk			if (oidp)
38012623Sphk				*oidp = *oidpp;
38112623Sphk			return (0);
38212623Sphk		}
38312623Sphk
38412623Sphk		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
38512623Sphk			break;
38612623Sphk
38712623Sphk		if ((*oidpp)->oid_handler)
38812623Sphk			break;
38912623Sphk
39012623Sphk		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
39112623Sphk		j = lsp->ls_length;
39212623Sphk		oidpp = (struct sysctl_oid **)lsp->ls_items;
39312623Sphk		name = p+1;
39412623Sphk		for (p = name; *p && *p != '.'; p++)
39512623Sphk				;
39612623Sphk		i = *p;
39712623Sphk		if (i == '.')
39812623Sphk			*p = '\0';
39912623Sphk	}
40012623Sphk	return ENOENT;
40112623Sphk}
40212623Sphk
40312623Sphkstatic int
40412623Sphksysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
40512623Sphk{
40612623Sphk	char *p;
40712623Sphk	int error, oid[CTL_MAXNAME], len;
40812623Sphk	struct sysctl_oid *op = 0;
40912623Sphk
41012623Sphk	if (!req->newlen)
41112623Sphk		return ENOENT;
41212623Sphk
41312623Sphk	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
41412623Sphk
41512623Sphk	error = SYSCTL_IN(req, p, req->newlen);
41612623Sphk	if (error) {
41712623Sphk		free(p, M_SYSCTL);
41812623Sphk		return (error);
41912623Sphk	}
42012623Sphk
42112623Sphk	p [req->newlen] = '\0';
42212623Sphk
42312623Sphk	error = name2oid(p, oid, &len, &op);
42412623Sphk
42512623Sphk	free(p, M_SYSCTL);
42612623Sphk
42712623Sphk	if (error)
42812623Sphk		return (error);
42912623Sphk
43012650Sphk	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
43112623Sphk	return (error);
43212623Sphk}
43312623Sphk
43412910SphkSYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
43512623Sphk	sysctl_sysctl_name2oid, "I", "");
43612623Sphk
43712623Sphkstatic int
43812623Sphksysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
43912623Sphk{
44012650Sphk	int *name = (int *) arg1, error;
44112623Sphk	u_int namelen = arg2;
44212623Sphk	int indx, j;
44312623Sphk	struct sysctl_oid **oidpp;
44412623Sphk	struct linker_set *lsp = &sysctl_;
44512623Sphk
44612623Sphk	j = lsp->ls_length;
44712623Sphk	oidpp = (struct sysctl_oid **) lsp->ls_items;
44812623Sphk
44912623Sphk	indx = 0;
45012623Sphk	while (j-- && indx < CTL_MAXNAME) {
45112623Sphk		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
45212623Sphk			indx++;
45312623Sphk			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
45412623Sphk				if ((*oidpp)->oid_handler)
45512623Sphk					goto found;
45612623Sphk				if (indx == namelen)
45712650Sphk					goto found;
45812623Sphk				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
45912623Sphk				j = lsp->ls_length;
46012623Sphk				oidpp = (struct sysctl_oid **)lsp->ls_items;
46112623Sphk			} else {
46212623Sphk				if (indx != namelen)
46312623Sphk					return EISDIR;
46412623Sphk				goto found;
46512623Sphk			}
46612623Sphk		} else {
46712623Sphk			oidpp++;
46812623Sphk		}
46912623Sphk	}
47012623Sphk	return ENOENT;
47112623Sphkfound:
47212623Sphk	if (!(*oidpp)->oid_fmt)
47312623Sphk		return ENOENT;
47412650Sphk	error = SYSCTL_OUT(req,
47512650Sphk		&(*oidpp)->oid_kind, sizeof((*oidpp)->oid_kind));
47612650Sphk	if (!error)
47712650Sphk		error = SYSCTL_OUT(req, (*oidpp)->oid_fmt,
47812650Sphk			strlen((*oidpp)->oid_fmt)+1);
47912650Sphk	return (error);
48012623Sphk}
48112623Sphk
48212623Sphk
48312623SphkSYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
48412623Sphk
48512243Sphk/*
48612623Sphk * Default "handler" functions.
48712623Sphk */
48812623Sphk
48912623Sphk/*
49012243Sphk * Handle an integer, signed or unsigned.
49112243Sphk * Two cases:
49212243Sphk *     a variable:  point arg1 at it.
49312243Sphk *     a constant:  pass it in arg2.
49412243Sphk */
49512243Sphk
49611865Sphkint
49711865Sphksysctl_handle_int SYSCTL_HANDLER_ARGS
49811863Sphk{
49912243Sphk	int error = 0;
50011863Sphk
50112243Sphk	if (arg1)
50212243Sphk		error = SYSCTL_OUT(req, arg1, sizeof(int));
50312243Sphk	else if (arg2)
50412243Sphk		error = SYSCTL_OUT(req, &arg2, sizeof(int));
50511863Sphk
50612243Sphk	if (error || !req->newptr)
50712243Sphk		return (error);
50811863Sphk
50912243Sphk	if (!arg1)
51012243Sphk		error = EPERM;
51112243Sphk	else
51212243Sphk		error = SYSCTL_IN(req, arg1, sizeof(int));
51312243Sphk	return (error);
51411863Sphk}
51511863Sphk
51612243Sphk/*
51712243Sphk * Handle our generic '\0' terminated 'C' string.
51812243Sphk * Two cases:
51912243Sphk * 	a variable string:  point arg1 at it, arg2 is max length.
52012243Sphk * 	a constant string:  point arg1 at it, arg2 is zero.
52112243Sphk */
52212243Sphk
52311865Sphkint
52411865Sphksysctl_handle_string SYSCTL_HANDLER_ARGS
52511863Sphk{
52612243Sphk	int error=0;
52711863Sphk
52812297Sphk	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
52911863Sphk
53012260Sphk	if (error || !req->newptr || !arg2)
53112243Sphk		return (error);
53211863Sphk
53312243Sphk	if ((req->newlen - req->newidx) > arg2) {
53412243Sphk		error = E2BIG;
53512243Sphk	} else {
53612243Sphk		arg2 = (req->newlen - req->newidx);
53712243Sphk		error = SYSCTL_IN(req, arg1, arg2);
53812243Sphk		((char *)arg1)[arg2] = '\0';
53911863Sphk	}
54012131Sphk
54112131Sphk	return (error);
54211863Sphk}
54311863Sphk
54412243Sphk/*
54512243Sphk * Handle any kind of opaque data.
54612243Sphk * arg1 points to it, arg2 is the size.
54712243Sphk */
54812243Sphk
54911865Sphkint
55011865Sphksysctl_handle_opaque SYSCTL_HANDLER_ARGS
55111863Sphk{
55212243Sphk	int error;
55312243Sphk
55412243Sphk	error = SYSCTL_OUT(req, arg1, arg2);
55512243Sphk
55612243Sphk	if (error || !req->newptr)
55712243Sphk		return (error);
55812243Sphk
55912243Sphk	error = SYSCTL_IN(req, arg1, arg2);
56012243Sphk
56112243Sphk	return (error);
56212243Sphk}
56312243Sphk
56412260Sphk/*
56512260Sphk * Transfer functions to/from kernel space.
56612260Sphk * XXX: rather untested at this point
56712260Sphk */
56812260Sphkstatic int
56912910Sphksysctl_old_kernel(struct sysctl_req *req, const void *p, int l)
57012243Sphk{
57112260Sphk	int i = 0;
57212260Sphk
57312260Sphk	if (req->oldptr) {
57412260Sphk		i = min(req->oldlen - req->oldidx, l);
57512260Sphk		if (i > 0)
57612260Sphk			bcopy(p, req->oldptr + req->oldidx, i);
57712243Sphk	}
57812260Sphk	req->oldidx += l;
57912243Sphk	if (i != l)
58011863Sphk		return (ENOMEM);
58112260Sphk	return (0);
58211863Sphk
58312243Sphk}
58412243Sphk
58512260Sphkstatic int
58612910Sphksysctl_new_kernel(struct sysctl_req *req, const void *p, int l)
58712243Sphk{
58812260Sphk	if (!req->newptr)
58912260Sphk		return 0;
59012260Sphk	if (req->newlen - req->newidx < l)
59111863Sphk		return (EINVAL);
59213155Speter	bcopy(p, req->newptr + req->newidx, l);
59312243Sphk	req->newidx += l;
59412131Sphk	return (0);
59511863Sphk}
59611863Sphk
59712260Sphk/*
59812260Sphk * Transfer function to/from user space.
59912260Sphk */
60012260Sphkstatic int
60112910Sphksysctl_old_user(struct sysctl_req *req, const void *p, int l)
60212243Sphk{
60312260Sphk	int error = 0, i = 0;
60412243Sphk
60512429Sphk	if (req->lock == 1 && req->oldptr) {
60612429Sphk		vslock(req->oldptr, req->oldlen);
60712429Sphk		req->lock = 2;
60812429Sphk	}
60912260Sphk	if (req->oldptr) {
61012260Sphk		i = min(req->oldlen - req->oldidx, l);
61112260Sphk		if (i > 0)
61212260Sphk			error  = copyout(p, req->oldptr + req->oldidx, i);
61312260Sphk	}
61412260Sphk	req->oldidx += l;
61512243Sphk	if (error)
61612243Sphk		return (error);
61712260Sphk	if (req->oldptr && i < l)
61812243Sphk		return (ENOMEM);
61912260Sphk	return (0);
62012243Sphk}
62112243Sphk
62212260Sphkstatic int
62312243Sphksysctl_new_user(struct sysctl_req *req, void *p, int l)
62412243Sphk{
62512285Sphk	int error;
62612260Sphk
62712260Sphk	if (!req->newptr)
62812260Sphk		return 0;
62912260Sphk	if (req->newlen - req->newidx < l)
63012243Sphk		return (EINVAL);
63112243Sphk	error = copyin(req->newptr + req->newidx, p, l);
63212243Sphk	req->newidx += l;
63312243Sphk	return (error);
63412243Sphk}
63512243Sphk
6361541Srgrimes/*
63712131Sphk * Traverse our tree, and find the right node, execute whatever it points
63812131Sphk * at, and return the resulting error code.
63912131Sphk */
64012131Sphk
6411541Srgrimesint
64212131Sphksysctl_root SYSCTL_HANDLER_ARGS
64312131Sphk{
64412131Sphk	int *name = (int *) arg1;
64512623Sphk	u_int namelen = arg2;
64612131Sphk	int indx, i, j;
64712131Sphk	struct sysctl_oid **oidpp;
64812131Sphk	struct linker_set *lsp = &sysctl_;
64912131Sphk
65012131Sphk	j = lsp->ls_length;
65112131Sphk	oidpp = (struct sysctl_oid **) lsp->ls_items;
65212131Sphk
65312131Sphk	indx = 0;
65412131Sphk	while (j-- && indx < CTL_MAXNAME) {
65512152Sphk		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
65612131Sphk			indx++;
65712429Sphk			if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
65812429Sphk				req->lock = 0;
65912131Sphk			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
66012131Sphk				if ((*oidpp)->oid_handler)
66112131Sphk					goto found;
66212243Sphk				if (indx == namelen)
66312131Sphk					return ENOENT;
66412131Sphk				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
66512131Sphk				j = lsp->ls_length;
66612131Sphk				oidpp = (struct sysctl_oid **)lsp->ls_items;
66712131Sphk			} else {
66812243Sphk				if (indx != namelen)
66912131Sphk					return EISDIR;
67012131Sphk				goto found;
67112131Sphk			}
67212131Sphk		} else {
67312131Sphk			oidpp++;
67412131Sphk		}
67512131Sphk	}
67612260Sphk	return ENOENT;
67712131Sphkfound:
67812131Sphk	/* If writing isn't allowed */
67912243Sphk	if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR))
68012131Sphk		return (EPERM);
68112131Sphk
68212910Sphk	/* Most likely only root can write */
68312910Sphk	if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
68412910Sphk	    req->newptr && req->p &&
68512910Sphk	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
68612910Sphk		return (i);
68712910Sphk
68812243Sphk	if (!(*oidpp)->oid_handler)
68912131Sphk		return EINVAL;
69012131Sphk
69112131Sphk	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
69212131Sphk		i = ((*oidpp)->oid_handler) (*oidpp,
69312131Sphk					name + indx, namelen - indx,
69412243Sphk					req);
69512131Sphk	} else {
69612131Sphk		i = ((*oidpp)->oid_handler) (*oidpp,
69712131Sphk					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
69812243Sphk					req);
69912131Sphk	}
70012131Sphk	return (i);
70112131Sphk}
70212131Sphk
70312221Sbde#ifndef _SYS_SYSPROTO_H_
70412171Sphkstruct sysctl_args {
70512171Sphk	int	*name;
70612171Sphk	u_int	namelen;
70712171Sphk	void	*old;
70812171Sphk	size_t	*oldlenp;
70912171Sphk	void	*new;
71012171Sphk	size_t	newlen;
71112171Sphk};
71212221Sbde#endif
71312171Sphk
71412131Sphkint
71512429Sphk__sysctl(struct proc *p, struct sysctl_args *uap, int *retval)
7161541Srgrimes{
71712260Sphk	int error, i, j, name[CTL_MAXNAME];
7181541Srgrimes
7191541Srgrimes	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
7201541Srgrimes		return (EINVAL);
72111863Sphk
7223308Sphk 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
7233308Sphk 	if (error)
7241541Srgrimes		return (error);
7251541Srgrimes
72612260Sphk	error = userland_sysctl(p, name, uap->namelen,
72712171Sphk		uap->old, uap->oldlenp, 0,
72812260Sphk		uap->new, uap->newlen, &j);
72912260Sphk	if (error && error != ENOMEM)
73012260Sphk		return (error);
73112260Sphk	if (uap->oldlenp) {
73212260Sphk		i = copyout(&j, uap->oldlenp, sizeof(j));
73312260Sphk		if (i)
73412260Sphk			return (i);
73512260Sphk	}
73612260Sphk	return (error);
73712171Sphk}
73812171Sphk
73912171Sphk/*
74012171Sphk * This is used from various compatibility syscalls too.  That's why name
74112171Sphk * must be in kernel space.
74212171Sphk */
74312171Sphkint
74412171Sphkuserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval)
74512171Sphk{
74612429Sphk	int error = 0;
74712243Sphk	struct sysctl_req req;
74812171Sphk
74912243Sphk	bzero(&req, sizeof req);
75012243Sphk
75112285Sphk	req.p = p;
75212285Sphk
75312171Sphk	if (oldlenp) {
75412171Sphk		if (inkernel) {
75512243Sphk			req.oldlen = *oldlenp;
75612171Sphk		} else {
75712260Sphk			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
75812171Sphk			if (error)
75912171Sphk				return (error);
76012171Sphk		}
76112171Sphk	}
76212171Sphk
76312243Sphk	if (old) {
76412243Sphk		if (!useracc(old, req.oldlen, B_WRITE))
76512243Sphk			return (EFAULT);
76612243Sphk		req.oldptr= old;
76712243Sphk	}
76812131Sphk
76912171Sphk	if (newlen) {
77012243Sphk		if (!useracc(new, req.newlen, B_READ))
77112243Sphk			return (EFAULT);
77212243Sphk		req.newlen = newlen;
77312243Sphk		req.newptr = new;
77411863Sphk	}
77512131Sphk
77612243Sphk	req.oldfunc = sysctl_old_user;
77712243Sphk	req.newfunc = sysctl_new_user;
77812429Sphk	req.lock = 1;
77911863Sphk
78012429Sphk	/* XXX this should probably be done in a general way */
78112429Sphk	while (memlock.sl_lock) {
78212429Sphk		memlock.sl_want = 1;
78312429Sphk		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
78412429Sphk		memlock.sl_locked++;
78512429Sphk	}
78612429Sphk	memlock.sl_lock = 1;
78712429Sphk
78812243Sphk	error = sysctl_root(0, name, namelen, &req);
78912243Sphk
79012429Sphk	if (req.lock == 2)
79112429Sphk		vsunlock(req.oldptr, req.oldlen, B_WRITE);
79212429Sphk
79312429Sphk	memlock.sl_lock = 0;
79412429Sphk
79512429Sphk	if (memlock.sl_want) {
79612429Sphk		memlock.sl_want = 0;
79712429Sphk		wakeup((caddr_t)&memlock);
79812429Sphk	}
79912429Sphk
80012260Sphk	if (error && error != ENOMEM)
80112260Sphk		return (error);
80212260Sphk
80312260Sphk	if (retval) {
80412260Sphk		if (req.oldptr && req.oldidx > req.oldlen)
80512243Sphk			*retval = req.oldlen;
80612260Sphk		else
80712260Sphk			*retval = req.oldidx;
80811863Sphk	}
80912260Sphk	return (error);
8101541Srgrimes}
8111541Srgrimes
8121541Srgrimes#ifdef COMPAT_43
8131541Srgrimes#include <sys/socket.h>
81415103Sphk#include <vm/vm_param.h>
81515103Sphk
8161541Srgrimes#define	KINFO_PROC		(0<<8)
8171541Srgrimes#define	KINFO_RT		(1<<8)
8181541Srgrimes#define	KINFO_VNODE		(2<<8)
8191541Srgrimes#define	KINFO_FILE		(3<<8)
8201541Srgrimes#define	KINFO_METER		(4<<8)
8211541Srgrimes#define	KINFO_LOADAVG		(5<<8)
8221541Srgrimes#define	KINFO_CLOCKRATE		(6<<8)
8231541Srgrimes
8249455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
8259455Speter#define	KINFO_BSDI_SYSINFO	(101<<8)
8269455Speter
8279455Speter/*
8289455Speter * XXX this is bloat, but I hope it's better here than on the potentially
8299455Speter * limited kernel stack...  -Peter
8309455Speter */
8319455Speter
83212819Sphkstatic struct {
8339455Speter	int	bsdi_machine;		/* "i386" on BSD/386 */
8349455Speter/*      ^^^ this is an offset to the string, relative to the struct start */
8359455Speter	char	*pad0;
8369455Speter	long	pad1;
8379455Speter	long	pad2;
8389455Speter	long	pad3;
8399455Speter	u_long	pad4;
8409455Speter	u_long	pad5;
8419455Speter	u_long	pad6;
8429455Speter
8439455Speter	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
8449455Speter	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
8459455Speter	long	pad7;
8469455Speter	long	pad8;
8479455Speter	char	*pad9;
8489455Speter
8499455Speter	long	pad10;
8509455Speter	long	pad11;
8519455Speter	int	pad12;
8529455Speter	long	pad13;
8539455Speter	quad_t	pad14;
8549455Speter	long	pad15;
8559455Speter
8569455Speter	struct	timeval pad16;
8579455Speter	/* we dont set this, because BSDI's uname used gethostname() instead */
8589455Speter	int	bsdi_hostname;		/* hostname on BSD/386 */
8599455Speter
8609455Speter	/* the actual string data is appended here */
8619455Speter
8629455Speter} bsdi_si;
8639455Speter/*
8649455Speter * this data is appended to the end of the bsdi_si structure during copyout.
8659455Speter * The "char *" offsets are relative to the base of the bsdi_si struct.
8669455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
8679455Speter * should not exceed the length of the buffer here... (or else!! :-)
8689455Speter */
86912819Sphkstatic char bsdi_strings[80];	/* It had better be less than this! */
8709455Speter
87112221Sbde#ifndef _SYS_SYSPROTO_H_
8721541Srgrimesstruct getkerninfo_args {
8731541Srgrimes	int	op;
8741541Srgrimes	char	*where;
8751541Srgrimes	int	*size;
8761541Srgrimes	int	arg;
8771541Srgrimes};
87812221Sbde#endif
8791541Srgrimes
8801549Srgrimesint
88112429Sphkogetkerninfo(struct proc *p, struct getkerninfo_args *uap, int *retval)
8821541Srgrimes{
88312171Sphk	int error, name[6];
8841541Srgrimes	u_int size;
8851541Srgrimes
8861541Srgrimes	switch (uap->op & 0xff00) {
8871541Srgrimes
8881541Srgrimes	case KINFO_RT:
88912171Sphk		name[0] = CTL_NET;
89012171Sphk		name[1] = PF_ROUTE;
89112171Sphk		name[2] = 0;
89212171Sphk		name[3] = (uap->op & 0xff0000) >> 16;
89312171Sphk		name[4] = uap->op & 0xff;
89412171Sphk		name[5] = uap->arg;
89512171Sphk		error = userland_sysctl(p, name, 6, uap->where, uap->size,
89612429Sphk			0, 0, 0, &size);
8971541Srgrimes		break;
8981541Srgrimes
8991541Srgrimes	case KINFO_VNODE:
90012171Sphk		name[0] = CTL_KERN;
90112171Sphk		name[1] = KERN_VNODE;
90212171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
90312429Sphk			0, 0, 0, &size);
9041541Srgrimes		break;
9051541Srgrimes
9061541Srgrimes	case KINFO_PROC:
90712171Sphk		name[0] = CTL_KERN;
90812171Sphk		name[1] = KERN_PROC;
90912171Sphk		name[2] = uap->op & 0xff;
91012171Sphk		name[3] = uap->arg;
91112171Sphk		error = userland_sysctl(p, name, 4, uap->where, uap->size,
91212429Sphk			0, 0, 0, &size);
9131541Srgrimes		break;
9141541Srgrimes
9151541Srgrimes	case KINFO_FILE:
91612171Sphk		name[0] = CTL_KERN;
91712171Sphk		name[1] = KERN_FILE;
91812171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
91912429Sphk			0, 0, 0, &size);
9201541Srgrimes		break;
9211541Srgrimes
9221541Srgrimes	case KINFO_METER:
92312171Sphk		name[0] = CTL_VM;
92412171Sphk		name[1] = VM_METER;
92512171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
92612429Sphk			0, 0, 0, &size);
9271541Srgrimes		break;
9281541Srgrimes
9291541Srgrimes	case KINFO_LOADAVG:
93012171Sphk		name[0] = CTL_VM;
93112171Sphk		name[1] = VM_LOADAVG;
93212171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
93312429Sphk			0, 0, 0, &size);
9341541Srgrimes		break;
9351541Srgrimes
9361541Srgrimes	case KINFO_CLOCKRATE:
93712171Sphk		name[0] = CTL_KERN;
93812171Sphk		name[1] = KERN_CLOCKRATE;
93912171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
94012429Sphk			0, 0, 0, &size);
9411541Srgrimes		break;
9421541Srgrimes
9439455Speter	case KINFO_BSDI_SYSINFO: {
9449455Speter		/*
9459455Speter		 * this is pretty crude, but it's just enough for uname()
9469455Speter		 * from BSDI's 1.x libc to work.
9479455Speter		 *
9489455Speter		 * In particular, it doesn't return the same results when
9499455Speter		 * the supplied buffer is too small.  BSDI's version apparently
9509455Speter		 * will return the amount copied, and set the *size to how
9519455Speter		 * much was needed.  The emulation framework here isn't capable
9529455Speter		 * of that, so we just set both to the amount copied.
9539455Speter		 * BSDI's 2.x product apparently fails with ENOMEM in this
9549455Speter		 * scenario.
9559455Speter		 */
9569455Speter
9579455Speter		u_int needed;
9589455Speter		u_int left;
9599455Speter		char *s;
9609455Speter
9619455Speter		bzero((char *)&bsdi_si, sizeof(bsdi_si));
9629455Speter		bzero(bsdi_strings, sizeof(bsdi_strings));
9639455Speter
9649455Speter		s = bsdi_strings;
9659455Speter
9669455Speter		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
9679455Speter		strcpy(s, ostype);
9689455Speter		s += strlen(s) + 1;
9699455Speter
9709455Speter		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
9719455Speter		strcpy(s, osrelease);
9729455Speter		s += strlen(s) + 1;
9739455Speter
9749455Speter		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
9759455Speter		strcpy(s, machine);
9769455Speter		s += strlen(s) + 1;
9779455Speter
9789455Speter		needed = sizeof(bsdi_si) + (s - bsdi_strings);
9799455Speter
9809455Speter		if (uap->where == NULL) {
9819455Speter			/* process is asking how much buffer to supply.. */
9829455Speter			size = needed;
9839455Speter			error = 0;
9849455Speter			break;
9859455Speter		}
9869455Speter
9879455Speter
9889455Speter		/* if too much buffer supplied, trim it down */
9899455Speter		if (size > needed)
9909455Speter			size = needed;
9919455Speter
9929455Speter		/* how much of the buffer is remaining */
9939455Speter		left = size;
9949455Speter
9959455Speter		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
9969455Speter			break;
9979455Speter
9989455Speter		/* is there any point in continuing? */
9999455Speter		if (left > sizeof(bsdi_si)) {
10009455Speter			left -= sizeof(bsdi_si);
10019455Speter			error = copyout(&bsdi_strings,
10029455Speter					uap->where + sizeof(bsdi_si), left);
10039455Speter		}
10049455Speter		break;
10059455Speter	}
10069455Speter
10071541Srgrimes	default:
10081541Srgrimes		return (EOPNOTSUPP);
10091541Srgrimes	}
10101541Srgrimes	if (error)
10111541Srgrimes		return (error);
10121541Srgrimes	*retval = size;
10131541Srgrimes	if (uap->size)
10141541Srgrimes		error = copyout((caddr_t)&size, (caddr_t)uap->size,
10151541Srgrimes		    sizeof(size));
10161541Srgrimes	return (error);
10171541Srgrimes}
10181541Srgrimes#endif /* COMPAT_43 */
1019