kern_sysctl.c revision 31778
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
4031778Seivind * $Id: kern_sysctl.c,v 1.73 1997/11/06 19:29:15 phk Exp $
411541Srgrimes */
421541Srgrimes
4331778Seivind#include "opt_compat.h"
4431778Seivind
451541Srgrimes#include <sys/param.h>
4624744Sbde#include <sys/buf.h>
471541Srgrimes#include <sys/kernel.h>
481541Srgrimes#include <sys/sysctl.h>
4912623Sphk#include <sys/malloc.h>
5012662Sdg#include <sys/proc.h>
5115103Sphk#include <sys/systm.h>
5215103Sphk#include <sys/sysproto.h>
5312645Sbde#include <vm/vm.h>
5412662Sdg#include <vm/vm_extern.h>
5512645Sbde
5630354Sphkstatic MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
5730309Sphk
5812429Sphk/*
5912429Sphk * Locking and stats
6012429Sphk */
6112429Sphkstatic struct sysctl_lock {
6212429Sphk	int	sl_lock;
6312429Sphk	int	sl_want;
6412429Sphk	int	sl_locked;
6512429Sphk} memlock;
6612429Sphk
6712429Sphkstatic int sysctl_root SYSCTL_HANDLER_ARGS;
6812429Sphk
6912152Sphkextern struct linker_set sysctl_;
7012152Sphk
7112623Sphk/*
7212623Sphk * Initialization of the MIB tree.
7312623Sphk *
7412623Sphk * Order by number in each linker_set.
7512623Sphk */
7612429Sphk
7712429Sphkstatic int
7812197Sbdesysctl_order_cmp(const void *a, const void *b)
7912152Sphk{
8018025Sbde	struct sysctl_oid const * const *pa;
8118025Sbde	struct sysctl_oid const * const *pb;
8212197Sbde
8318025Sbde	pa = (struct sysctl_oid const * const *)a;
8418025Sbde	pb = (struct sysctl_oid const * const *)b;
8512197Sbde	if (*pa == NULL)
8612197Sbde		return (1);
8712197Sbde	if (*pb == NULL)
8812197Sbde		return (-1);
8912152Sphk	return ((*pa)->oid_number - (*pb)->oid_number);
9012152Sphk}
9112131Sphk
9212152Sphkstatic void
9312152Sphksysctl_order(void *arg)
9412152Sphk{
9512623Sphk	int j, k;
9612152Sphk	struct linker_set *l = (struct linker_set *) arg;
9712152Sphk	struct sysctl_oid **oidpp;
9812152Sphk
9912623Sphk	/* First, find the highest oid we have */
10012152Sphk	j = l->ls_length;
10112152Sphk	oidpp = (struct sysctl_oid **) l->ls_items;
10215241Sphk	for (k = 0; j--; oidpp++) {
10315241Sphk		if ((*oidpp)->oid_arg1 == arg) {
10415241Sphk			*oidpp = 0;
10515241Sphk			continue;
10615241Sphk		}
10712623Sphk		if (*oidpp && (*oidpp)->oid_number > k)
10812623Sphk			k = (*oidpp)->oid_number;
10915241Sphk	}
11012623Sphk
11112623Sphk	/* Next, replace all OID_AUTO oids with new numbers */
11212623Sphk	j = l->ls_length;
11312623Sphk	oidpp = (struct sysctl_oid **) l->ls_items;
11412623Sphk	k += 100;
11512623Sphk	for (; j--; oidpp++)
11612623Sphk		if (*oidpp && (*oidpp)->oid_number == OID_AUTO)
11712623Sphk			(*oidpp)->oid_number = k++;
11812623Sphk
11912623Sphk	/* Finally: sort by oid */
12012623Sphk	j = l->ls_length;
12112623Sphk	oidpp = (struct sysctl_oid **) l->ls_items;
12212152Sphk	for (; j--; oidpp++) {
12312152Sphk		if (!*oidpp)
12412152Sphk			continue;
12512243Sphk		if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
12612152Sphk			if (!(*oidpp)->oid_handler)
12712152Sphk				sysctl_order((*oidpp)->oid_arg1);
12812152Sphk	}
12912152Sphk	qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
13012152Sphk		sysctl_order_cmp);
13112152Sphk}
13212152Sphk
13312243SphkSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
13412152Sphk
13512623Sphk/*
13612623Sphk * "Staff-functions"
13712623Sphk *
13812650Sphk * These functions implement a presently undocumented interface
13912650Sphk * used by the sysctl program to walk the tree, and get the type
14012650Sphk * so it can print the value.
14112650Sphk * This interface is under work and consideration, and should probably
14212650Sphk * be killed with a big axe by the first person who can find the time.
14312650Sphk * (be aware though, that the proper interface isn't as obvious as it
14412650Sphk * may seem, there are various conflicting requirements.
14512650Sphk *
14612623Sphk * {0,0}	printf the entire MIB-tree.
14712623Sphk * {0,1,...}	return the name of the "..." OID.
14812623Sphk * {0,2,...}	return the next OID.
14912623Sphk * {0,3}	return the OID of the name in "new"
15012650Sphk * {0,4,...}	return the kind & format info for the "..." OID.
15112623Sphk */
15212623Sphk
15312152Sphkstatic void
15412243Sphksysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
15512152Sphk{
15612243Sphk	int j, k;
15712152Sphk	struct sysctl_oid **oidpp;
15812152Sphk
15912152Sphk	j = l->ls_length;
16012152Sphk	oidpp = (struct sysctl_oid **) l->ls_items;
16112152Sphk	for (; j--; oidpp++) {
16212152Sphk
16312152Sphk		if (!*oidpp)
16412152Sphk			continue;
16512152Sphk
16612152Sphk		for (k=0; k<i; k++)
16712152Sphk			printf(" ");
16812152Sphk
16912152Sphk		printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
17012152Sphk
17112152Sphk		printf("%c%c",
17212152Sphk			(*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
17312152Sphk			(*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
17412152Sphk
17515241Sphk		if ((*oidpp)->oid_handler)
17615241Sphk			printf(" *Handler");
17715241Sphk
17812152Sphk		switch ((*oidpp)->oid_kind & CTLTYPE) {
17912243Sphk			case CTLTYPE_NODE:
18015241Sphk				printf(" Node\n");
18115241Sphk				if (!(*oidpp)->oid_handler) {
18212152Sphk					sysctl_sysctl_debug_dump_node(
18312243Sphk						(*oidpp)->oid_arg1, i+2);
18412152Sphk				}
18512152Sphk				break;
18612152Sphk			case CTLTYPE_INT:    printf(" Int\n"); break;
18712152Sphk			case CTLTYPE_STRING: printf(" String\n"); break;
18812152Sphk			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
18912152Sphk			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
19012152Sphk			default:	     printf("\n");
19112152Sphk		}
19212152Sphk
19312152Sphk	}
19412152Sphk}
19512152Sphk
19612152Sphkstatic int
19712152Sphksysctl_sysctl_debug SYSCTL_HANDLER_ARGS
19812152Sphk{
19912243Sphk	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
20012152Sphk	return ENOENT;
20112152Sphk}
20212152Sphk
20312152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
20412623Sphk	0, 0, sysctl_sysctl_debug, "-", "");
20512152Sphk
20612623Sphkstatic int
20712623Sphksysctl_sysctl_name SYSCTL_HANDLER_ARGS
20812623Sphk{
20912623Sphk	int *name = (int *) arg1;
21012623Sphk	u_int namelen = arg2;
21112623Sphk	int i, j, error = 0;
21212623Sphk	struct sysctl_oid **oidpp;
21312623Sphk	struct linker_set *lsp = &sysctl_;
21412623Sphk	char buf[10];
21512131Sphk
21612623Sphk	while (namelen) {
21712623Sphk		if (!lsp) {
21812623Sphk			sprintf(buf,"%d",*name);
21912623Sphk			if (req->oldidx)
22012623Sphk				error = SYSCTL_OUT(req, ".", 1);
22112623Sphk			if (!error)
22212623Sphk				error = SYSCTL_OUT(req, buf, strlen(buf));
22312623Sphk			if (error)
22412623Sphk				return (error);
22512623Sphk			namelen--;
22612623Sphk			name++;
22712623Sphk			continue;
22812623Sphk		}
22912623Sphk		oidpp = (struct sysctl_oid **) lsp->ls_items;
23012623Sphk		j = lsp->ls_length;
23112623Sphk		lsp = 0;
23212623Sphk		for (i = 0; i < j; i++, oidpp++) {
23312623Sphk			if (*oidpp && ((*oidpp)->oid_number != *name))
23412623Sphk				continue;
23512131Sphk
23612623Sphk			if (req->oldidx)
23712623Sphk				error = SYSCTL_OUT(req, ".", 1);
23812623Sphk			if (!error)
23912623Sphk				error = SYSCTL_OUT(req, (*oidpp)->oid_name,
24012623Sphk					strlen((*oidpp)->oid_name));
24112623Sphk			if (error)
24212623Sphk				return (error);
24312623Sphk
24412623Sphk			namelen--;
24512623Sphk			name++;
24612623Sphk
24712623Sphk			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
24812623Sphk				break;
24912623Sphk
25012623Sphk			if ((*oidpp)->oid_handler)
25112623Sphk				break;
25212623Sphk
25312623Sphk			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
25412623Sphk			break;
25512623Sphk		}
25612623Sphk	}
25712623Sphk	return (SYSCTL_OUT(req, "", 1));
25812623Sphk}
25912623Sphk
26012623SphkSYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
26112623Sphk
26212623Sphkstatic int
26312623Sphksysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen,
26412623Sphk	int *next, int *len, int level, struct sysctl_oid **oidp)
26512623Sphk{
26612623Sphk	int i, j;
26712623Sphk	struct sysctl_oid **oidpp;
26812623Sphk
26912623Sphk	oidpp = (struct sysctl_oid **) lsp->ls_items;
27012623Sphk	j = lsp->ls_length;
27112623Sphk	*len = level;
27212623Sphk	for (i = 0; i < j; i++, oidpp++) {
27312623Sphk		if (!*oidpp)
27412623Sphk			continue;
27512623Sphk
27612623Sphk		*next = (*oidpp)->oid_number;
27712623Sphk		*oidp = *oidpp;
27812623Sphk
27912623Sphk		if (!namelen) {
28012623Sphk			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
28112623Sphk				return 0;
28212623Sphk			if ((*oidpp)->oid_handler)
28312623Sphk				/* We really should call the handler here...*/
28412623Sphk				return 0;
28512623Sphk			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
28615241Sphk			if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
28715241Sphk				len, level+1, oidp))
28815241Sphk				return 0;
28915241Sphk			goto next;
29012623Sphk		}
29112623Sphk
29212623Sphk		if ((*oidpp)->oid_number < *name)
29312623Sphk			continue;
29412623Sphk
29512623Sphk		if ((*oidpp)->oid_number > *name) {
29612623Sphk			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
29712623Sphk				return 0;
29812623Sphk			if ((*oidpp)->oid_handler)
29912623Sphk				return 0;
30012623Sphk			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
30112623Sphk			if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
30212623Sphk				next+1, len, level+1, oidp))
30312623Sphk				return (0);
30415241Sphk			goto next;
30512623Sphk		}
30612623Sphk		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
30712623Sphk			continue;
30812623Sphk
30912623Sphk		if ((*oidpp)->oid_handler)
31012623Sphk			continue;
31112623Sphk
31212623Sphk		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
31312623Sphk		if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
31412623Sphk			len, level+1, oidp))
31512623Sphk			return (0);
31615241Sphk	next:
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));
50320506Sbde	else
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)
57617971Sbde			bcopy(p, (char *)req->oldptr + req->oldidx, i);
57712243Sphk	}
57812260Sphk	req->oldidx += l;
57916282Snate	if (req->oldptr && i != l)
58011863Sphk		return (ENOMEM);
58112260Sphk	return (0);
58212243Sphk}
58312243Sphk
58412260Sphkstatic int
58516282Snatesysctl_new_kernel(struct sysctl_req *req, void *p, int l)
58612243Sphk{
58712260Sphk	if (!req->newptr)
58812260Sphk		return 0;
58912260Sphk	if (req->newlen - req->newidx < l)
59011863Sphk		return (EINVAL);
59117971Sbde	bcopy((char *)req->newptr + req->newidx, p, l);
59212243Sphk	req->newidx += l;
59312131Sphk	return (0);
59411863Sphk}
59511863Sphk
59616282Snateint
59716282Snatekernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, int *retval)
59816282Snate{
59916282Snate	int error = 0;
60016282Snate	struct sysctl_req req;
60116282Snate
60216282Snate	bzero(&req, sizeof req);
60316282Snate
60416282Snate	req.p = p;
60516282Snate
60616282Snate	if (oldlenp) {
60716282Snate		req.oldlen = *oldlenp;
60816282Snate	}
60916282Snate
61016282Snate	if (old) {
61116282Snate		req.oldptr= old;
61216282Snate	}
61316282Snate
61416282Snate	if (newlen) {
61516282Snate		req.newlen = newlen;
61616282Snate		req.newptr = new;
61716282Snate	}
61816282Snate
61916282Snate	req.oldfunc = sysctl_old_kernel;
62016282Snate	req.newfunc = sysctl_new_kernel;
62116282Snate	req.lock = 1;
62216282Snate
62316282Snate	/* XXX this should probably be done in a general way */
62416282Snate	while (memlock.sl_lock) {
62516282Snate		memlock.sl_want = 1;
62616282Snate		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
62716282Snate		memlock.sl_locked++;
62816282Snate	}
62916282Snate	memlock.sl_lock = 1;
63016282Snate
63116282Snate	error = sysctl_root(0, name, namelen, &req);
63216282Snate
63316282Snate	if (req.lock == 2)
63416282Snate		vsunlock(req.oldptr, req.oldlen, B_WRITE);
63516282Snate
63616282Snate	memlock.sl_lock = 0;
63716282Snate
63816282Snate	if (memlock.sl_want) {
63916282Snate		memlock.sl_want = 0;
64016282Snate		wakeup((caddr_t)&memlock);
64116282Snate	}
64216282Snate
64316282Snate	if (error && error != ENOMEM)
64416282Snate		return (error);
64516282Snate
64616282Snate	if (retval) {
64716282Snate		if (req.oldptr && req.oldidx > req.oldlen)
64816282Snate			*retval = req.oldlen;
64916282Snate		else
65016282Snate			*retval = req.oldidx;
65116282Snate	}
65216282Snate	return (error);
65316282Snate}
65416282Snate
65512260Sphk/*
65612260Sphk * Transfer function to/from user space.
65712260Sphk */
65812260Sphkstatic int
65912910Sphksysctl_old_user(struct sysctl_req *req, const void *p, int l)
66012243Sphk{
66112260Sphk	int error = 0, i = 0;
66212243Sphk
66312429Sphk	if (req->lock == 1 && req->oldptr) {
66412429Sphk		vslock(req->oldptr, req->oldlen);
66512429Sphk		req->lock = 2;
66612429Sphk	}
66712260Sphk	if (req->oldptr) {
66812260Sphk		i = min(req->oldlen - req->oldidx, l);
66912260Sphk		if (i > 0)
67017971Sbde			error = copyout(p, (char *)req->oldptr + req->oldidx,
67117971Sbde					i);
67212260Sphk	}
67312260Sphk	req->oldidx += l;
67412243Sphk	if (error)
67512243Sphk		return (error);
67612260Sphk	if (req->oldptr && i < l)
67712243Sphk		return (ENOMEM);
67812260Sphk	return (0);
67912243Sphk}
68012243Sphk
68112260Sphkstatic int
68212243Sphksysctl_new_user(struct sysctl_req *req, void *p, int l)
68312243Sphk{
68412285Sphk	int error;
68512260Sphk
68612260Sphk	if (!req->newptr)
68712260Sphk		return 0;
68812260Sphk	if (req->newlen - req->newidx < l)
68912243Sphk		return (EINVAL);
69017971Sbde	error = copyin((char *)req->newptr + req->newidx, p, l);
69112243Sphk	req->newidx += l;
69212243Sphk	return (error);
69312243Sphk}
69412243Sphk
6951541Srgrimes/*
69612131Sphk * Traverse our tree, and find the right node, execute whatever it points
69712131Sphk * at, and return the resulting error code.
69812131Sphk */
69912131Sphk
7001541Srgrimesint
70112131Sphksysctl_root SYSCTL_HANDLER_ARGS
70212131Sphk{
70312131Sphk	int *name = (int *) arg1;
70412623Sphk	u_int namelen = arg2;
70512131Sphk	int indx, i, j;
70612131Sphk	struct sysctl_oid **oidpp;
70712131Sphk	struct linker_set *lsp = &sysctl_;
70812131Sphk
70912131Sphk	j = lsp->ls_length;
71012131Sphk	oidpp = (struct sysctl_oid **) lsp->ls_items;
71112131Sphk
71212131Sphk	indx = 0;
71312131Sphk	while (j-- && indx < CTL_MAXNAME) {
71412152Sphk		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
71512131Sphk			indx++;
71612429Sphk			if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
71712429Sphk				req->lock = 0;
71812131Sphk			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
71912131Sphk				if ((*oidpp)->oid_handler)
72012131Sphk					goto found;
72112243Sphk				if (indx == namelen)
72212131Sphk					return ENOENT;
72312131Sphk				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
72412131Sphk				j = lsp->ls_length;
72512131Sphk				oidpp = (struct sysctl_oid **)lsp->ls_items;
72612131Sphk			} else {
72712243Sphk				if (indx != namelen)
72812131Sphk					return EISDIR;
72912131Sphk				goto found;
73012131Sphk			}
73112131Sphk		} else {
73212131Sphk			oidpp++;
73312131Sphk		}
73412131Sphk	}
73512260Sphk	return ENOENT;
73612131Sphkfound:
73712131Sphk	/* If writing isn't allowed */
73812243Sphk	if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR))
73912131Sphk		return (EPERM);
74012131Sphk
74112910Sphk	/* Most likely only root can write */
74212910Sphk	if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
74312910Sphk	    req->newptr && req->p &&
74412910Sphk	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
74512910Sphk		return (i);
74612910Sphk
74712243Sphk	if (!(*oidpp)->oid_handler)
74812131Sphk		return EINVAL;
74912131Sphk
75012131Sphk	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
75112131Sphk		i = ((*oidpp)->oid_handler) (*oidpp,
75212131Sphk					name + indx, namelen - indx,
75312243Sphk					req);
75412131Sphk	} else {
75512131Sphk		i = ((*oidpp)->oid_handler) (*oidpp,
75612131Sphk					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
75712243Sphk					req);
75812131Sphk	}
75912131Sphk	return (i);
76012131Sphk}
76112131Sphk
76212221Sbde#ifndef _SYS_SYSPROTO_H_
76312171Sphkstruct sysctl_args {
76412171Sphk	int	*name;
76512171Sphk	u_int	namelen;
76612171Sphk	void	*old;
76712171Sphk	size_t	*oldlenp;
76812171Sphk	void	*new;
76912171Sphk	size_t	newlen;
77012171Sphk};
77112221Sbde#endif
77212171Sphk
77312131Sphkint
77430994Sphk__sysctl(struct proc *p, struct sysctl_args *uap)
7751541Srgrimes{
77612260Sphk	int error, i, j, name[CTL_MAXNAME];
7771541Srgrimes
7781541Srgrimes	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
7791541Srgrimes		return (EINVAL);
78011863Sphk
7813308Sphk 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
7823308Sphk 	if (error)
7831541Srgrimes		return (error);
7841541Srgrimes
78512260Sphk	error = userland_sysctl(p, name, uap->namelen,
78612171Sphk		uap->old, uap->oldlenp, 0,
78712260Sphk		uap->new, uap->newlen, &j);
78812260Sphk	if (error && error != ENOMEM)
78912260Sphk		return (error);
79012260Sphk	if (uap->oldlenp) {
79112260Sphk		i = copyout(&j, uap->oldlenp, sizeof(j));
79212260Sphk		if (i)
79312260Sphk			return (i);
79412260Sphk	}
79512260Sphk	return (error);
79612171Sphk}
79712171Sphk
79812171Sphk/*
79912171Sphk * This is used from various compatibility syscalls too.  That's why name
80012171Sphk * must be in kernel space.
80112171Sphk */
80212171Sphkint
80312171Sphkuserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval)
80412171Sphk{
80512429Sphk	int error = 0;
80616159Sphk	struct sysctl_req req, req2;
80712171Sphk
80812243Sphk	bzero(&req, sizeof req);
80912243Sphk
81012285Sphk	req.p = p;
81112285Sphk
81212171Sphk	if (oldlenp) {
81312171Sphk		if (inkernel) {
81412243Sphk			req.oldlen = *oldlenp;
81512171Sphk		} else {
81612260Sphk			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
81712171Sphk			if (error)
81812171Sphk				return (error);
81912171Sphk		}
82012171Sphk	}
82112171Sphk
82212243Sphk	if (old) {
82312243Sphk		if (!useracc(old, req.oldlen, B_WRITE))
82412243Sphk			return (EFAULT);
82512243Sphk		req.oldptr= old;
82612243Sphk	}
82712131Sphk
82812171Sphk	if (newlen) {
82912243Sphk		if (!useracc(new, req.newlen, B_READ))
83012243Sphk			return (EFAULT);
83112243Sphk		req.newlen = newlen;
83212243Sphk		req.newptr = new;
83311863Sphk	}
83412131Sphk
83512243Sphk	req.oldfunc = sysctl_old_user;
83612243Sphk	req.newfunc = sysctl_new_user;
83712429Sphk	req.lock = 1;
83811863Sphk
83912429Sphk	/* XXX this should probably be done in a general way */
84012429Sphk	while (memlock.sl_lock) {
84112429Sphk		memlock.sl_want = 1;
84212429Sphk		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
84312429Sphk		memlock.sl_locked++;
84412429Sphk	}
84512429Sphk	memlock.sl_lock = 1;
84612429Sphk
84716159Sphk	do {
84816159Sphk	    req2 = req;
84916159Sphk	    error = sysctl_root(0, name, namelen, &req2);
85016159Sphk	} while (error == EAGAIN);
85112243Sphk
85216159Sphk	req = req2;
85312429Sphk	if (req.lock == 2)
85412429Sphk		vsunlock(req.oldptr, req.oldlen, B_WRITE);
85512429Sphk
85612429Sphk	memlock.sl_lock = 0;
85712429Sphk
85812429Sphk	if (memlock.sl_want) {
85912429Sphk		memlock.sl_want = 0;
86012429Sphk		wakeup((caddr_t)&memlock);
86112429Sphk	}
86212429Sphk
86312260Sphk	if (error && error != ENOMEM)
86412260Sphk		return (error);
86512260Sphk
86612260Sphk	if (retval) {
86712260Sphk		if (req.oldptr && req.oldidx > req.oldlen)
86812243Sphk			*retval = req.oldlen;
86912260Sphk		else
87012260Sphk			*retval = req.oldidx;
87111863Sphk	}
87212260Sphk	return (error);
8731541Srgrimes}
8741541Srgrimes
8751541Srgrimes#ifdef COMPAT_43
8761541Srgrimes#include <sys/socket.h>
87715103Sphk#include <vm/vm_param.h>
87815103Sphk
8791541Srgrimes#define	KINFO_PROC		(0<<8)
8801541Srgrimes#define	KINFO_RT		(1<<8)
8811541Srgrimes#define	KINFO_VNODE		(2<<8)
8821541Srgrimes#define	KINFO_FILE		(3<<8)
8831541Srgrimes#define	KINFO_METER		(4<<8)
8841541Srgrimes#define	KINFO_LOADAVG		(5<<8)
8851541Srgrimes#define	KINFO_CLOCKRATE		(6<<8)
8861541Srgrimes
8879455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
8889455Speter#define	KINFO_BSDI_SYSINFO	(101<<8)
8899455Speter
8909455Speter/*
8919455Speter * XXX this is bloat, but I hope it's better here than on the potentially
8929455Speter * limited kernel stack...  -Peter
8939455Speter */
8949455Speter
89512819Sphkstatic struct {
8969455Speter	int	bsdi_machine;		/* "i386" on BSD/386 */
8979455Speter/*      ^^^ this is an offset to the string, relative to the struct start */
8989455Speter	char	*pad0;
8999455Speter	long	pad1;
9009455Speter	long	pad2;
9019455Speter	long	pad3;
9029455Speter	u_long	pad4;
9039455Speter	u_long	pad5;
9049455Speter	u_long	pad6;
9059455Speter
9069455Speter	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
9079455Speter	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
9089455Speter	long	pad7;
9099455Speter	long	pad8;
9109455Speter	char	*pad9;
9119455Speter
9129455Speter	long	pad10;
9139455Speter	long	pad11;
9149455Speter	int	pad12;
9159455Speter	long	pad13;
9169455Speter	quad_t	pad14;
9179455Speter	long	pad15;
9189455Speter
9199455Speter	struct	timeval pad16;
9209455Speter	/* we dont set this, because BSDI's uname used gethostname() instead */
9219455Speter	int	bsdi_hostname;		/* hostname on BSD/386 */
9229455Speter
9239455Speter	/* the actual string data is appended here */
9249455Speter
9259455Speter} bsdi_si;
9269455Speter/*
9279455Speter * this data is appended to the end of the bsdi_si structure during copyout.
9289455Speter * The "char *" offsets are relative to the base of the bsdi_si struct.
9299455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
9309455Speter * should not exceed the length of the buffer here... (or else!! :-)
9319455Speter */
93212819Sphkstatic char bsdi_strings[80];	/* It had better be less than this! */
9339455Speter
93412221Sbde#ifndef _SYS_SYSPROTO_H_
9351541Srgrimesstruct getkerninfo_args {
9361541Srgrimes	int	op;
9371541Srgrimes	char	*where;
9381541Srgrimes	int	*size;
9391541Srgrimes	int	arg;
9401541Srgrimes};
94112221Sbde#endif
9421541Srgrimes
9431549Srgrimesint
94430994Sphkogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
9451541Srgrimes{
94612171Sphk	int error, name[6];
9471541Srgrimes	u_int size;
9481541Srgrimes
9491541Srgrimes	switch (uap->op & 0xff00) {
9501541Srgrimes
9511541Srgrimes	case KINFO_RT:
95212171Sphk		name[0] = CTL_NET;
95312171Sphk		name[1] = PF_ROUTE;
95412171Sphk		name[2] = 0;
95512171Sphk		name[3] = (uap->op & 0xff0000) >> 16;
95612171Sphk		name[4] = uap->op & 0xff;
95712171Sphk		name[5] = uap->arg;
95812171Sphk		error = userland_sysctl(p, name, 6, uap->where, uap->size,
95912429Sphk			0, 0, 0, &size);
9601541Srgrimes		break;
9611541Srgrimes
9621541Srgrimes	case KINFO_VNODE:
96312171Sphk		name[0] = CTL_KERN;
96412171Sphk		name[1] = KERN_VNODE;
96512171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
96612429Sphk			0, 0, 0, &size);
9671541Srgrimes		break;
9681541Srgrimes
9691541Srgrimes	case KINFO_PROC:
97012171Sphk		name[0] = CTL_KERN;
97112171Sphk		name[1] = KERN_PROC;
97212171Sphk		name[2] = uap->op & 0xff;
97312171Sphk		name[3] = uap->arg;
97412171Sphk		error = userland_sysctl(p, name, 4, uap->where, uap->size,
97512429Sphk			0, 0, 0, &size);
9761541Srgrimes		break;
9771541Srgrimes
9781541Srgrimes	case KINFO_FILE:
97912171Sphk		name[0] = CTL_KERN;
98012171Sphk		name[1] = KERN_FILE;
98112171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
98212429Sphk			0, 0, 0, &size);
9831541Srgrimes		break;
9841541Srgrimes
9851541Srgrimes	case KINFO_METER:
98612171Sphk		name[0] = CTL_VM;
98712171Sphk		name[1] = VM_METER;
98812171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
98912429Sphk			0, 0, 0, &size);
9901541Srgrimes		break;
9911541Srgrimes
9921541Srgrimes	case KINFO_LOADAVG:
99312171Sphk		name[0] = CTL_VM;
99412171Sphk		name[1] = VM_LOADAVG;
99512171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
99612429Sphk			0, 0, 0, &size);
9971541Srgrimes		break;
9981541Srgrimes
9991541Srgrimes	case KINFO_CLOCKRATE:
100012171Sphk		name[0] = CTL_KERN;
100112171Sphk		name[1] = KERN_CLOCKRATE;
100212171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
100312429Sphk			0, 0, 0, &size);
10041541Srgrimes		break;
10051541Srgrimes
10069455Speter	case KINFO_BSDI_SYSINFO: {
10079455Speter		/*
10089455Speter		 * this is pretty crude, but it's just enough for uname()
10099455Speter		 * from BSDI's 1.x libc to work.
10109455Speter		 *
10119455Speter		 * In particular, it doesn't return the same results when
10129455Speter		 * the supplied buffer is too small.  BSDI's version apparently
10139455Speter		 * will return the amount copied, and set the *size to how
10149455Speter		 * much was needed.  The emulation framework here isn't capable
10159455Speter		 * of that, so we just set both to the amount copied.
10169455Speter		 * BSDI's 2.x product apparently fails with ENOMEM in this
10179455Speter		 * scenario.
10189455Speter		 */
10199455Speter
10209455Speter		u_int needed;
10219455Speter		u_int left;
10229455Speter		char *s;
10239455Speter
10249455Speter		bzero((char *)&bsdi_si, sizeof(bsdi_si));
10259455Speter		bzero(bsdi_strings, sizeof(bsdi_strings));
10269455Speter
10279455Speter		s = bsdi_strings;
10289455Speter
10299455Speter		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
10309455Speter		strcpy(s, ostype);
10319455Speter		s += strlen(s) + 1;
10329455Speter
10339455Speter		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
10349455Speter		strcpy(s, osrelease);
10359455Speter		s += strlen(s) + 1;
10369455Speter
10379455Speter		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
10389455Speter		strcpy(s, machine);
10399455Speter		s += strlen(s) + 1;
10409455Speter
10419455Speter		needed = sizeof(bsdi_si) + (s - bsdi_strings);
10429455Speter
10439455Speter		if (uap->where == NULL) {
10449455Speter			/* process is asking how much buffer to supply.. */
10459455Speter			size = needed;
10469455Speter			error = 0;
10479455Speter			break;
10489455Speter		}
10499455Speter
10509455Speter
10519455Speter		/* if too much buffer supplied, trim it down */
10529455Speter		if (size > needed)
10539455Speter			size = needed;
10549455Speter
10559455Speter		/* how much of the buffer is remaining */
10569455Speter		left = size;
10579455Speter
10589455Speter		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
10599455Speter			break;
10609455Speter
10619455Speter		/* is there any point in continuing? */
10629455Speter		if (left > sizeof(bsdi_si)) {
10639455Speter			left -= sizeof(bsdi_si);
10649455Speter			error = copyout(&bsdi_strings,
10659455Speter					uap->where + sizeof(bsdi_si), left);
10669455Speter		}
10679455Speter		break;
10689455Speter	}
10699455Speter
10701541Srgrimes	default:
10711541Srgrimes		return (EOPNOTSUPP);
10721541Srgrimes	}
10731541Srgrimes	if (error)
10741541Srgrimes		return (error);
107530994Sphk	p->p_retval[0] = size;
10761541Srgrimes	if (uap->size)
10771541Srgrimes		error = copyout((caddr_t)&size, (caddr_t)uap->size,
10781541Srgrimes		    sizeof(size));
10791541Srgrimes	return (error);
10801541Srgrimes}
10811541Srgrimes#endif /* COMPAT_43 */
1082