kern_sysctl.c revision 44972
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
4044972Sphk * $Id: kern_sysctl.c,v 1.84 1999/02/16 10:49:48 dfr 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
6944078Sdfrstruct sysctl_oid_list sysctl__children; /* root list */
7012152Sphk
7112623Sphk/*
7212623Sphk * Initialization of the MIB tree.
7312623Sphk *
7444078Sdfr * Order by number in each list.
7512623Sphk */
7612429Sphk
7744078Sdfrvoid sysctl_register_oid(struct sysctl_oid *oidp)
7812152Sphk{
7944078Sdfr	struct sysctl_oid_list *parent = oidp->oid_parent;
8044078Sdfr	struct sysctl_oid *p;
8144078Sdfr	struct sysctl_oid *q;
8244078Sdfr	int n;
8312197Sbde
8444078Sdfr	/*
8544078Sdfr	 * If this oid has a number OID_AUTO, give it a number which
8644078Sdfr	 * is greater than any current oid.  Make sure it is at least
8744078Sdfr	 * 100 to leave space for pre-assigned oid numbers.
8844078Sdfr	 */
8944078Sdfr	if (oidp->oid_number == OID_AUTO) {
9044078Sdfr		/* First, find the highest oid in the parent list >99 */
9144078Sdfr		n = 99;
9244078Sdfr		SLIST_FOREACH(p, parent, oid_link) {
9344078Sdfr			if (p->oid_number > n)
9444078Sdfr				n = p->oid_number;
9544078Sdfr		}
9644078Sdfr		oidp->oid_number = n + 1;
9744078Sdfr	}
9844078Sdfr
9944078Sdfr	/*
10044078Sdfr	 * Insert the oid into the parent's list in order.
10144078Sdfr	 */
10244078Sdfr	q = NULL;
10344078Sdfr	SLIST_FOREACH(p, parent, oid_link) {
10444078Sdfr		if (oidp->oid_number < p->oid_number)
10544078Sdfr			break;
10644078Sdfr		q = p;
10744078Sdfr	}
10844078Sdfr	if (q)
10944078Sdfr		SLIST_INSERT_AFTER(q, oidp, oid_link);
11044078Sdfr	else
11144078Sdfr		SLIST_INSERT_HEAD(parent, oidp, oid_link);
11212152Sphk}
11312131Sphk
11444078Sdfrvoid sysctl_unregister_oid(struct sysctl_oid *oidp)
11512152Sphk{
11644078Sdfr	SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
11744078Sdfr}
11812152Sphk
11944078Sdfr/*
12044078Sdfr * Bulk-register all the oids in a linker_set.
12144078Sdfr */
12244078Sdfrvoid sysctl_register_set(struct linker_set *lsp)
12344078Sdfr{
12444078Sdfr	int count = lsp->ls_length;
12544078Sdfr	int i;
12644078Sdfr	for (i = 0; i < count; i++)
12744078Sdfr		sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);
12844078Sdfr}
12912623Sphk
13044078Sdfrvoid sysctl_unregister_set(struct linker_set *lsp)
13144078Sdfr{
13244078Sdfr	int count = lsp->ls_length;
13344078Sdfr	int i;
13444078Sdfr	for (i = 0; i < count; i++)
13544078Sdfr		sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]);
13612152Sphk}
13712152Sphk
13844078Sdfr/*
13944078Sdfr * Register the kernel's oids on startup.
14044078Sdfr */
14144078Sdfrextern struct linker_set sysctl_set;
14212152Sphk
14344078Sdfrstatic void sysctl_register_all(void *arg)
14438869Sbde{
14544078Sdfr	sysctl_register_set(&sysctl_set);
14638869Sbde}
14738869Sbde
14844078SdfrSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
14944078Sdfr
15012623Sphk/*
15112623Sphk * "Staff-functions"
15212623Sphk *
15312650Sphk * These functions implement a presently undocumented interface
15412650Sphk * used by the sysctl program to walk the tree, and get the type
15512650Sphk * so it can print the value.
15612650Sphk * This interface is under work and consideration, and should probably
15712650Sphk * be killed with a big axe by the first person who can find the time.
15812650Sphk * (be aware though, that the proper interface isn't as obvious as it
15912650Sphk * may seem, there are various conflicting requirements.
16012650Sphk *
16112623Sphk * {0,0}	printf the entire MIB-tree.
16212623Sphk * {0,1,...}	return the name of the "..." OID.
16342467Sphk * {0,2,...}	return the next OID.
16412623Sphk * {0,3}	return the OID of the name in "new"
16512650Sphk * {0,4,...}	return the kind & format info for the "..." OID.
16612623Sphk */
16712623Sphk
16812152Sphkstatic void
16944078Sdfrsysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
17012152Sphk{
17144078Sdfr	int k;
17244078Sdfr	struct sysctl_oid *oidp;
17312152Sphk
17444078Sdfr	SLIST_FOREACH(oidp, l, oid_link) {
17512152Sphk
17612152Sphk		for (k=0; k<i; k++)
17712152Sphk			printf(" ");
17812152Sphk
17944078Sdfr		printf("%d %s ", oidp->oid_number, oidp->oid_name);
18012152Sphk
18112152Sphk		printf("%c%c",
18244078Sdfr			oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
18344078Sdfr			oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
18412152Sphk
18544078Sdfr		if (oidp->oid_handler)
18615241Sphk			printf(" *Handler");
18715241Sphk
18844078Sdfr		switch (oidp->oid_kind & CTLTYPE) {
18912243Sphk			case CTLTYPE_NODE:
19015241Sphk				printf(" Node\n");
19144078Sdfr				if (!oidp->oid_handler) {
19212152Sphk					sysctl_sysctl_debug_dump_node(
19344078Sdfr						oidp->oid_arg1, i+2);
19412152Sphk				}
19512152Sphk				break;
19612152Sphk			case CTLTYPE_INT:    printf(" Int\n"); break;
19712152Sphk			case CTLTYPE_STRING: printf(" String\n"); break;
19812152Sphk			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
19912152Sphk			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
20012152Sphk			default:	     printf("\n");
20112152Sphk		}
20212152Sphk
20312152Sphk	}
20412152Sphk}
20512152Sphk
20612152Sphkstatic int
20712152Sphksysctl_sysctl_debug SYSCTL_HANDLER_ARGS
20812152Sphk{
20944078Sdfr	sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
21012152Sphk	return ENOENT;
21112152Sphk}
21212152Sphk
21312152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
21412623Sphk	0, 0, sysctl_sysctl_debug, "-", "");
21512152Sphk
21612623Sphkstatic int
21712623Sphksysctl_sysctl_name SYSCTL_HANDLER_ARGS
21812623Sphk{
21912623Sphk	int *name = (int *) arg1;
22012623Sphk	u_int namelen = arg2;
22144078Sdfr	int error = 0;
22244078Sdfr	struct sysctl_oid *oid;
22344972Sphk	struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
22412623Sphk	char buf[10];
22512131Sphk
22612623Sphk	while (namelen) {
22712623Sphk		if (!lsp) {
22841514Sarchie			snprintf(buf,sizeof(buf),"%d",*name);
22912623Sphk			if (req->oldidx)
23012623Sphk				error = SYSCTL_OUT(req, ".", 1);
23112623Sphk			if (!error)
23212623Sphk				error = SYSCTL_OUT(req, buf, strlen(buf));
23312623Sphk			if (error)
23412623Sphk				return (error);
23512623Sphk			namelen--;
23612623Sphk			name++;
23712623Sphk			continue;
23812623Sphk		}
23944972Sphk		lsp2 = 0;
24044078Sdfr		SLIST_FOREACH(oid, lsp, oid_link) {
24144078Sdfr			if (oid->oid_number != *name)
24212623Sphk				continue;
24312131Sphk
24412623Sphk			if (req->oldidx)
24512623Sphk				error = SYSCTL_OUT(req, ".", 1);
24612623Sphk			if (!error)
24744078Sdfr				error = SYSCTL_OUT(req, oid->oid_name,
24844078Sdfr					strlen(oid->oid_name));
24912623Sphk			if (error)
25012623Sphk				return (error);
25112623Sphk
25212623Sphk			namelen--;
25312623Sphk			name++;
25412623Sphk
25544972Sphk			if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
25612623Sphk				break;
25712623Sphk
25844078Sdfr			if (oid->oid_handler)
25912623Sphk				break;
26012623Sphk
26144972Sphk			lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
26212623Sphk			break;
26312623Sphk		}
26444972Sphk		lsp = lsp2;
26512623Sphk	}
26612623Sphk	return (SYSCTL_OUT(req, "", 1));
26712623Sphk}
26812623Sphk
26912623SphkSYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
27012623Sphk
27112623Sphkstatic int
27244078Sdfrsysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen,
27344078Sdfr	int *next, int *len, int level, struct sysctl_oid **oidpp)
27412623Sphk{
27544078Sdfr	struct sysctl_oid *oidp;
27612623Sphk
27712623Sphk	*len = level;
27844078Sdfr	SLIST_FOREACH(oidp, lsp, oid_link) {
27944078Sdfr		*next = oidp->oid_number;
28044078Sdfr		*oidpp = oidp;
28112623Sphk
28212623Sphk		if (!namelen) {
28344078Sdfr			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
28412623Sphk				return 0;
28544078Sdfr			if (oidp->oid_handler)
28612623Sphk				/* We really should call the handler here...*/
28712623Sphk				return 0;
28844078Sdfr			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
28915241Sphk			if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
29044078Sdfr				len, level+1, oidpp))
29115241Sphk				return 0;
29215241Sphk			goto next;
29312623Sphk		}
29412623Sphk
29544078Sdfr		if (oidp->oid_number < *name)
29612623Sphk			continue;
29712623Sphk
29844078Sdfr		if (oidp->oid_number > *name) {
29944078Sdfr			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
30012623Sphk				return 0;
30144078Sdfr			if (oidp->oid_handler)
30212623Sphk				return 0;
30344078Sdfr			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
30412623Sphk			if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
30544078Sdfr				next+1, len, level+1, oidpp))
30612623Sphk				return (0);
30715241Sphk			goto next;
30812623Sphk		}
30944078Sdfr		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
31012623Sphk			continue;
31112623Sphk
31244078Sdfr		if (oidp->oid_handler)
31312623Sphk			continue;
31412623Sphk
31544078Sdfr		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
31612623Sphk		if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
31744078Sdfr			len, level+1, oidpp))
31812623Sphk			return (0);
31915241Sphk	next:
32012623Sphk		namelen = 1;
32112623Sphk		*len = level;
32212623Sphk	}
32312623Sphk	return 1;
32412623Sphk}
32512623Sphk
32612623Sphkstatic int
32712623Sphksysctl_sysctl_next SYSCTL_HANDLER_ARGS
32812623Sphk{
32912623Sphk	int *name = (int *) arg1;
33012623Sphk	u_int namelen = arg2;
33112623Sphk	int i, j, error;
33212623Sphk	struct sysctl_oid *oid;
33344078Sdfr	struct sysctl_oid_list *lsp = &sysctl__children;
33412623Sphk	int newoid[CTL_MAXNAME];
33512623Sphk
33612623Sphk	i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
33712623Sphk	if (i)
33812623Sphk		return ENOENT;
33912650Sphk	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
34012623Sphk	return (error);
34112623Sphk}
34212623Sphk
34312623SphkSYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
34412623Sphk
34512623Sphkstatic int
34644078Sdfrname2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
34712623Sphk{
34844078Sdfr	int i;
34944078Sdfr	struct sysctl_oid *oidp;
35044078Sdfr	struct sysctl_oid_list *lsp = &sysctl__children;
35112623Sphk	char *p;
35212623Sphk
35312623Sphk	if (!*name)
35412623Sphk		return ENOENT;
35512623Sphk
35612623Sphk	p = name + strlen(name) - 1 ;
35712623Sphk	if (*p == '.')
35812623Sphk		*p = '\0';
35912623Sphk
36012623Sphk	*len = 0;
36112623Sphk
36212623Sphk	for (p = name; *p && *p != '.'; p++)
36312623Sphk		;
36412623Sphk	i = *p;
36512623Sphk	if (i == '.')
36612623Sphk		*p = '\0';
36712623Sphk
36844078Sdfr	oidp = SLIST_FIRST(lsp);
36912623Sphk
37044078Sdfr	while (oidp && *len < CTL_MAXNAME) {
37144078Sdfr		if (strcmp(name, oidp->oid_name)) {
37244078Sdfr			oidp = SLIST_NEXT(oidp, oid_link);
37312623Sphk			continue;
37412623Sphk		}
37544078Sdfr		*oid++ = oidp->oid_number;
37612623Sphk		(*len)++;
37712623Sphk
37812623Sphk		if (!i) {
37944078Sdfr			if (oidpp)
38044078Sdfr				*oidpp = oidp;
38112623Sphk			return (0);
38212623Sphk		}
38312623Sphk
38444078Sdfr		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
38512623Sphk			break;
38612623Sphk
38744078Sdfr		if (oidp->oid_handler)
38812623Sphk			break;
38912623Sphk
39044078Sdfr		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
39144078Sdfr		oidp = SLIST_FIRST(lsp);
39212623Sphk		name = p+1;
39312623Sphk		for (p = name; *p && *p != '.'; p++)
39412623Sphk				;
39512623Sphk		i = *p;
39612623Sphk		if (i == '.')
39712623Sphk			*p = '\0';
39812623Sphk	}
39912623Sphk	return ENOENT;
40012623Sphk}
40112623Sphk
40212623Sphkstatic int
40312623Sphksysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
40412623Sphk{
40512623Sphk	char *p;
40612623Sphk	int error, oid[CTL_MAXNAME], len;
40712623Sphk	struct sysctl_oid *op = 0;
40812623Sphk
40912623Sphk	if (!req->newlen)
41012623Sphk		return ENOENT;
41112623Sphk
41212623Sphk	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
41312623Sphk
41412623Sphk	error = SYSCTL_IN(req, p, req->newlen);
41512623Sphk	if (error) {
41612623Sphk		free(p, M_SYSCTL);
41712623Sphk		return (error);
41812623Sphk	}
41912623Sphk
42012623Sphk	p [req->newlen] = '\0';
42112623Sphk
42212623Sphk	error = name2oid(p, oid, &len, &op);
42312623Sphk
42412623Sphk	free(p, M_SYSCTL);
42512623Sphk
42612623Sphk	if (error)
42712623Sphk		return (error);
42812623Sphk
42912650Sphk	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
43012623Sphk	return (error);
43112623Sphk}
43212623Sphk
43312910SphkSYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
43412623Sphk	sysctl_sysctl_name2oid, "I", "");
43512623Sphk
43612623Sphkstatic int
43712623Sphksysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
43812623Sphk{
43912650Sphk	int *name = (int *) arg1, error;
44012623Sphk	u_int namelen = arg2;
44144078Sdfr	int indx;
44244078Sdfr	struct sysctl_oid *oid;
44344078Sdfr	struct sysctl_oid_list *lsp = &sysctl__children;
44412623Sphk
44544078Sdfr	oid = SLIST_FIRST(lsp);
44612623Sphk
44712623Sphk	indx = 0;
44844078Sdfr	while (oid && indx < CTL_MAXNAME) {
44944078Sdfr		if (oid->oid_number == name[indx]) {
45012623Sphk			indx++;
45144078Sdfr			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
45244078Sdfr				if (oid->oid_handler)
45312623Sphk					goto found;
45412623Sphk				if (indx == namelen)
45512650Sphk					goto found;
45644078Sdfr				lsp = (struct sysctl_oid_list *)oid->oid_arg1;
45744078Sdfr				oid = SLIST_FIRST(lsp);
45812623Sphk			} else {
45912623Sphk				if (indx != namelen)
46012623Sphk					return EISDIR;
46112623Sphk				goto found;
46212623Sphk			}
46312623Sphk		} else {
46444078Sdfr			oid = SLIST_NEXT(oid, oid_link);
46512623Sphk		}
46612623Sphk	}
46712623Sphk	return ENOENT;
46812623Sphkfound:
46944078Sdfr	if (!oid->oid_fmt)
47012623Sphk		return ENOENT;
47112650Sphk	error = SYSCTL_OUT(req,
47244078Sdfr		&oid->oid_kind, sizeof(oid->oid_kind));
47312650Sphk	if (!error)
47444078Sdfr		error = SYSCTL_OUT(req, oid->oid_fmt,
47544078Sdfr			strlen(oid->oid_fmt)+1);
47612650Sphk	return (error);
47712623Sphk}
47812623Sphk
47942467Sphk
48012623SphkSYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
48112623Sphk
48212243Sphk/*
48312623Sphk * Default "handler" functions.
48412623Sphk */
48512623Sphk
48612623Sphk/*
48742095Sdfr * Handle an int, signed or unsigned.
48812243Sphk * Two cases:
48912243Sphk *     a variable:  point arg1 at it.
49012243Sphk *     a constant:  pass it in arg2.
49112243Sphk */
49212243Sphk
49311865Sphkint
49411865Sphksysctl_handle_int SYSCTL_HANDLER_ARGS
49511863Sphk{
49612243Sphk	int error = 0;
49711863Sphk
49812243Sphk	if (arg1)
49912243Sphk		error = SYSCTL_OUT(req, arg1, sizeof(int));
50020506Sbde	else
50112243Sphk		error = SYSCTL_OUT(req, &arg2, sizeof(int));
50211863Sphk
50312243Sphk	if (error || !req->newptr)
50412243Sphk		return (error);
50511863Sphk
50612243Sphk	if (!arg1)
50712243Sphk		error = EPERM;
50812243Sphk	else
50912243Sphk		error = SYSCTL_IN(req, arg1, sizeof(int));
51012243Sphk	return (error);
51111863Sphk}
51211863Sphk
51312243Sphk/*
51442095Sdfr * Handle a long, signed or unsigned.
51538517Sdfr * Two cases:
51638517Sdfr *     a variable:  point arg1 at it.
51738517Sdfr *     a constant:  pass it in arg2.
51838517Sdfr */
51938517Sdfr
52038517Sdfrint
52138517Sdfrsysctl_handle_long SYSCTL_HANDLER_ARGS
52238517Sdfr{
52338517Sdfr	int error = 0;
52438517Sdfr
52542095Sdfr	error = SYSCTL_OUT(req, arg1, sizeof(long));
52638517Sdfr
52738517Sdfr	if (error || !req->newptr)
52838517Sdfr		return (error);
52938517Sdfr
53038517Sdfr	if (!arg1)
53138517Sdfr		error = EPERM;
53238517Sdfr	else
53338517Sdfr		error = SYSCTL_IN(req, arg1, sizeof(long));
53438517Sdfr	return (error);
53538517Sdfr}
53638517Sdfr
53738517Sdfr/*
53812243Sphk * Handle our generic '\0' terminated 'C' string.
53912243Sphk * Two cases:
54012243Sphk * 	a variable string:  point arg1 at it, arg2 is max length.
54112243Sphk * 	a constant string:  point arg1 at it, arg2 is zero.
54212243Sphk */
54312243Sphk
54411865Sphkint
54511865Sphksysctl_handle_string SYSCTL_HANDLER_ARGS
54611863Sphk{
54712243Sphk	int error=0;
54811863Sphk
54912297Sphk	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
55011863Sphk
55112260Sphk	if (error || !req->newptr || !arg2)
55212243Sphk		return (error);
55311863Sphk
55412243Sphk	if ((req->newlen - req->newidx) > arg2) {
55512243Sphk		error = E2BIG;
55612243Sphk	} else {
55712243Sphk		arg2 = (req->newlen - req->newidx);
55812243Sphk		error = SYSCTL_IN(req, arg1, arg2);
55912243Sphk		((char *)arg1)[arg2] = '\0';
56011863Sphk	}
56112131Sphk
56212131Sphk	return (error);
56311863Sphk}
56411863Sphk
56512243Sphk/*
56612243Sphk * Handle any kind of opaque data.
56712243Sphk * arg1 points to it, arg2 is the size.
56812243Sphk */
56912243Sphk
57011865Sphkint
57111865Sphksysctl_handle_opaque SYSCTL_HANDLER_ARGS
57211863Sphk{
57312243Sphk	int error;
57412243Sphk
57512243Sphk	error = SYSCTL_OUT(req, arg1, arg2);
57612243Sphk
57712243Sphk	if (error || !req->newptr)
57812243Sphk		return (error);
57912243Sphk
58012243Sphk	error = SYSCTL_IN(req, arg1, arg2);
58112243Sphk
58212243Sphk	return (error);
58312243Sphk}
58412243Sphk
58512260Sphk/*
58612260Sphk * Transfer functions to/from kernel space.
58712260Sphk * XXX: rather untested at this point
58812260Sphk */
58912260Sphkstatic int
59038517Sdfrsysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
59112243Sphk{
59238517Sdfr	size_t i = 0;
59312260Sphk
59412260Sphk	if (req->oldptr) {
59538517Sdfr		i = l;
59638517Sdfr		if (i > req->oldlen - req->oldidx)
59738517Sdfr			i = req->oldlen - req->oldidx;
59812260Sphk		if (i > 0)
59917971Sbde			bcopy(p, (char *)req->oldptr + req->oldidx, i);
60012243Sphk	}
60112260Sphk	req->oldidx += l;
60216282Snate	if (req->oldptr && i != l)
60311863Sphk		return (ENOMEM);
60412260Sphk	return (0);
60512243Sphk}
60612243Sphk
60712260Sphkstatic int
60838517Sdfrsysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
60912243Sphk{
61012260Sphk	if (!req->newptr)
61112260Sphk		return 0;
61212260Sphk	if (req->newlen - req->newidx < l)
61311863Sphk		return (EINVAL);
61417971Sbde	bcopy((char *)req->newptr + req->newidx, p, l);
61512243Sphk	req->newidx += l;
61612131Sphk	return (0);
61711863Sphk}
61811863Sphk
61916282Snateint
62038517Sdfrkernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
62116282Snate{
62216282Snate	int error = 0;
62316282Snate	struct sysctl_req req;
62416282Snate
62516282Snate	bzero(&req, sizeof req);
62616282Snate
62716282Snate	req.p = p;
62816282Snate
62916282Snate	if (oldlenp) {
63016282Snate		req.oldlen = *oldlenp;
63116282Snate	}
63216282Snate
63316282Snate	if (old) {
63416282Snate		req.oldptr= old;
63516282Snate	}
63616282Snate
63716282Snate	if (newlen) {
63816282Snate		req.newlen = newlen;
63916282Snate		req.newptr = new;
64016282Snate	}
64116282Snate
64216282Snate	req.oldfunc = sysctl_old_kernel;
64316282Snate	req.newfunc = sysctl_new_kernel;
64416282Snate	req.lock = 1;
64516282Snate
64616282Snate	/* XXX this should probably be done in a general way */
64716282Snate	while (memlock.sl_lock) {
64816282Snate		memlock.sl_want = 1;
64916282Snate		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
65016282Snate		memlock.sl_locked++;
65116282Snate	}
65216282Snate	memlock.sl_lock = 1;
65316282Snate
65416282Snate	error = sysctl_root(0, name, namelen, &req);
65516282Snate
65616282Snate	if (req.lock == 2)
65716282Snate		vsunlock(req.oldptr, req.oldlen, B_WRITE);
65816282Snate
65916282Snate	memlock.sl_lock = 0;
66016282Snate
66116282Snate	if (memlock.sl_want) {
66216282Snate		memlock.sl_want = 0;
66316282Snate		wakeup((caddr_t)&memlock);
66416282Snate	}
66516282Snate
66616282Snate	if (error && error != ENOMEM)
66716282Snate		return (error);
66816282Snate
66916282Snate	if (retval) {
67016282Snate		if (req.oldptr && req.oldidx > req.oldlen)
67116282Snate			*retval = req.oldlen;
67216282Snate		else
67316282Snate			*retval = req.oldidx;
67416282Snate	}
67516282Snate	return (error);
67616282Snate}
67716282Snate
67812260Sphk/*
67912260Sphk * Transfer function to/from user space.
68012260Sphk */
68112260Sphkstatic int
68238517Sdfrsysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
68312243Sphk{
68438517Sdfr	int error = 0;
68538517Sdfr	size_t i = 0;
68612243Sphk
68712429Sphk	if (req->lock == 1 && req->oldptr) {
68812429Sphk		vslock(req->oldptr, req->oldlen);
68912429Sphk		req->lock = 2;
69012429Sphk	}
69112260Sphk	if (req->oldptr) {
69238517Sdfr		i = l;
69338517Sdfr		if (i > req->oldlen - req->oldidx)
69438517Sdfr			i = req->oldlen - req->oldidx;
69512260Sphk		if (i > 0)
69617971Sbde			error = copyout(p, (char *)req->oldptr + req->oldidx,
69717971Sbde					i);
69812260Sphk	}
69912260Sphk	req->oldidx += l;
70012243Sphk	if (error)
70112243Sphk		return (error);
70212260Sphk	if (req->oldptr && i < l)
70312243Sphk		return (ENOMEM);
70412260Sphk	return (0);
70512243Sphk}
70612243Sphk
70712260Sphkstatic int
70838517Sdfrsysctl_new_user(struct sysctl_req *req, void *p, size_t l)
70912243Sphk{
71012285Sphk	int error;
71112260Sphk
71212260Sphk	if (!req->newptr)
71312260Sphk		return 0;
71412260Sphk	if (req->newlen - req->newidx < l)
71512243Sphk		return (EINVAL);
71617971Sbde	error = copyin((char *)req->newptr + req->newidx, p, l);
71712243Sphk	req->newidx += l;
71812243Sphk	return (error);
71912243Sphk}
72012243Sphk
7211541Srgrimes/*
72212131Sphk * Traverse our tree, and find the right node, execute whatever it points
72312131Sphk * at, and return the resulting error code.
72412131Sphk */
72512131Sphk
7261541Srgrimesint
72712131Sphksysctl_root SYSCTL_HANDLER_ARGS
72812131Sphk{
72912131Sphk	int *name = (int *) arg1;
73012623Sphk	u_int namelen = arg2;
73144078Sdfr	int indx, i;
73244078Sdfr	struct sysctl_oid *oid;
73344078Sdfr	struct sysctl_oid_list *lsp = &sysctl__children;
73412131Sphk
73544078Sdfr	oid = SLIST_FIRST(lsp);
73612131Sphk
73712131Sphk	indx = 0;
73844078Sdfr	while (oid && indx < CTL_MAXNAME) {
73944078Sdfr		if (oid->oid_number == name[indx]) {
74012131Sphk			indx++;
74144078Sdfr			if (oid->oid_kind & CTLFLAG_NOLOCK)
74212429Sphk				req->lock = 0;
74344078Sdfr			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
74444078Sdfr				if (oid->oid_handler)
74512131Sphk					goto found;
74612243Sphk				if (indx == namelen)
74712131Sphk					return ENOENT;
74844078Sdfr				lsp = (struct sysctl_oid_list *)oid->oid_arg1;
74944078Sdfr				oid = SLIST_FIRST(lsp);
75012131Sphk			} else {
75112243Sphk				if (indx != namelen)
75212131Sphk					return EISDIR;
75312131Sphk				goto found;
75412131Sphk			}
75512131Sphk		} else {
75644078Sdfr			oid = SLIST_NEXT(oid, oid_link);
75712131Sphk		}
75812131Sphk	}
75912260Sphk	return ENOENT;
76012131Sphkfound:
76112131Sphk	/* If writing isn't allowed */
76244078Sdfr	if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
76344078Sdfr	    ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
76412131Sphk		return (EPERM);
76512131Sphk
76612910Sphk	/* Most likely only root can write */
76744078Sdfr	if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
76812910Sphk	    req->newptr && req->p &&
76912910Sphk	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
77012910Sphk		return (i);
77112910Sphk
77244078Sdfr	if (!oid->oid_handler)
77312131Sphk		return EINVAL;
77412131Sphk
77544078Sdfr	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
77644078Sdfr		i = (oid->oid_handler) (oid,
77712131Sphk					name + indx, namelen - indx,
77812243Sphk					req);
77912131Sphk	} else {
78044078Sdfr		i = (oid->oid_handler) (oid,
78144078Sdfr					oid->oid_arg1, oid->oid_arg2,
78212243Sphk					req);
78312131Sphk	}
78412131Sphk	return (i);
78512131Sphk}
78612131Sphk
78712221Sbde#ifndef _SYS_SYSPROTO_H_
78812171Sphkstruct sysctl_args {
78912171Sphk	int	*name;
79012171Sphk	u_int	namelen;
79112171Sphk	void	*old;
79212171Sphk	size_t	*oldlenp;
79312171Sphk	void	*new;
79412171Sphk	size_t	newlen;
79512171Sphk};
79612221Sbde#endif
79712171Sphk
79812131Sphkint
79930994Sphk__sysctl(struct proc *p, struct sysctl_args *uap)
8001541Srgrimes{
80138517Sdfr	int error, i, name[CTL_MAXNAME];
80238517Sdfr	size_t j;
8031541Srgrimes
8041541Srgrimes	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
8051541Srgrimes		return (EINVAL);
80611863Sphk
8073308Sphk 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
8083308Sphk 	if (error)
8091541Srgrimes		return (error);
8101541Srgrimes
81112260Sphk	error = userland_sysctl(p, name, uap->namelen,
81212171Sphk		uap->old, uap->oldlenp, 0,
81312260Sphk		uap->new, uap->newlen, &j);
81412260Sphk	if (error && error != ENOMEM)
81512260Sphk		return (error);
81612260Sphk	if (uap->oldlenp) {
81712260Sphk		i = copyout(&j, uap->oldlenp, sizeof(j));
81812260Sphk		if (i)
81912260Sphk			return (i);
82012260Sphk	}
82112260Sphk	return (error);
82212171Sphk}
82312171Sphk
82412171Sphk/*
82512171Sphk * This is used from various compatibility syscalls too.  That's why name
82612171Sphk * must be in kernel space.
82712171Sphk */
82812171Sphkint
82938517Sdfruserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
83012171Sphk{
83112429Sphk	int error = 0;
83216159Sphk	struct sysctl_req req, req2;
83312171Sphk
83412243Sphk	bzero(&req, sizeof req);
83512243Sphk
83612285Sphk	req.p = p;
83712285Sphk
83812171Sphk	if (oldlenp) {
83912171Sphk		if (inkernel) {
84012243Sphk			req.oldlen = *oldlenp;
84112171Sphk		} else {
84212260Sphk			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
84312171Sphk			if (error)
84412171Sphk				return (error);
84512171Sphk		}
84612171Sphk	}
84712171Sphk
84812243Sphk	if (old) {
84912243Sphk		if (!useracc(old, req.oldlen, B_WRITE))
85012243Sphk			return (EFAULT);
85112243Sphk		req.oldptr= old;
85212243Sphk	}
85312131Sphk
85412171Sphk	if (newlen) {
85512243Sphk		if (!useracc(new, req.newlen, B_READ))
85612243Sphk			return (EFAULT);
85712243Sphk		req.newlen = newlen;
85812243Sphk		req.newptr = new;
85911863Sphk	}
86012131Sphk
86112243Sphk	req.oldfunc = sysctl_old_user;
86212243Sphk	req.newfunc = sysctl_new_user;
86312429Sphk	req.lock = 1;
86411863Sphk
86512429Sphk	/* XXX this should probably be done in a general way */
86612429Sphk	while (memlock.sl_lock) {
86712429Sphk		memlock.sl_want = 1;
86812429Sphk		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
86912429Sphk		memlock.sl_locked++;
87012429Sphk	}
87112429Sphk	memlock.sl_lock = 1;
87212429Sphk
87316159Sphk	do {
87416159Sphk	    req2 = req;
87516159Sphk	    error = sysctl_root(0, name, namelen, &req2);
87616159Sphk	} while (error == EAGAIN);
87712243Sphk
87816159Sphk	req = req2;
87912429Sphk	if (req.lock == 2)
88012429Sphk		vsunlock(req.oldptr, req.oldlen, B_WRITE);
88112429Sphk
88212429Sphk	memlock.sl_lock = 0;
88312429Sphk
88412429Sphk	if (memlock.sl_want) {
88512429Sphk		memlock.sl_want = 0;
88612429Sphk		wakeup((caddr_t)&memlock);
88712429Sphk	}
88812429Sphk
88912260Sphk	if (error && error != ENOMEM)
89012260Sphk		return (error);
89112260Sphk
89212260Sphk	if (retval) {
89312260Sphk		if (req.oldptr && req.oldidx > req.oldlen)
89412243Sphk			*retval = req.oldlen;
89512260Sphk		else
89612260Sphk			*retval = req.oldidx;
89711863Sphk	}
89812260Sphk	return (error);
8991541Srgrimes}
9001541Srgrimes
9011541Srgrimes#ifdef COMPAT_43
9021541Srgrimes#include <sys/socket.h>
90315103Sphk#include <vm/vm_param.h>
90415103Sphk
9051541Srgrimes#define	KINFO_PROC		(0<<8)
9061541Srgrimes#define	KINFO_RT		(1<<8)
9071541Srgrimes#define	KINFO_VNODE		(2<<8)
9081541Srgrimes#define	KINFO_FILE		(3<<8)
9091541Srgrimes#define	KINFO_METER		(4<<8)
9101541Srgrimes#define	KINFO_LOADAVG		(5<<8)
9111541Srgrimes#define	KINFO_CLOCKRATE		(6<<8)
9121541Srgrimes
9139455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
9149455Speter#define	KINFO_BSDI_SYSINFO	(101<<8)
9159455Speter
9169455Speter/*
9179455Speter * XXX this is bloat, but I hope it's better here than on the potentially
9189455Speter * limited kernel stack...  -Peter
9199455Speter */
9209455Speter
92112819Sphkstatic struct {
9229455Speter	int	bsdi_machine;		/* "i386" on BSD/386 */
9239455Speter/*      ^^^ this is an offset to the string, relative to the struct start */
9249455Speter	char	*pad0;
9259455Speter	long	pad1;
9269455Speter	long	pad2;
9279455Speter	long	pad3;
9289455Speter	u_long	pad4;
9299455Speter	u_long	pad5;
9309455Speter	u_long	pad6;
9319455Speter
9329455Speter	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
9339455Speter	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
9349455Speter	long	pad7;
9359455Speter	long	pad8;
9369455Speter	char	*pad9;
9379455Speter
9389455Speter	long	pad10;
9399455Speter	long	pad11;
9409455Speter	int	pad12;
9419455Speter	long	pad13;
9429455Speter	quad_t	pad14;
9439455Speter	long	pad15;
9449455Speter
9459455Speter	struct	timeval pad16;
9469455Speter	/* we dont set this, because BSDI's uname used gethostname() instead */
9479455Speter	int	bsdi_hostname;		/* hostname on BSD/386 */
9489455Speter
9499455Speter	/* the actual string data is appended here */
9509455Speter
9519455Speter} bsdi_si;
9529455Speter/*
9539455Speter * this data is appended to the end of the bsdi_si structure during copyout.
9549455Speter * The "char *" offsets are relative to the base of the bsdi_si struct.
9559455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
9569455Speter * should not exceed the length of the buffer here... (or else!! :-)
9579455Speter */
95812819Sphkstatic char bsdi_strings[80];	/* It had better be less than this! */
9599455Speter
96012221Sbde#ifndef _SYS_SYSPROTO_H_
9611541Srgrimesstruct getkerninfo_args {
9621541Srgrimes	int	op;
9631541Srgrimes	char	*where;
96438864Sbde	size_t	*size;
9651541Srgrimes	int	arg;
9661541Srgrimes};
96712221Sbde#endif
9681541Srgrimes
9691549Srgrimesint
97030994Sphkogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
9711541Srgrimes{
97212171Sphk	int error, name[6];
97338517Sdfr	size_t size;
9741541Srgrimes
9751541Srgrimes	switch (uap->op & 0xff00) {
9761541Srgrimes
9771541Srgrimes	case KINFO_RT:
97812171Sphk		name[0] = CTL_NET;
97912171Sphk		name[1] = PF_ROUTE;
98012171Sphk		name[2] = 0;
98112171Sphk		name[3] = (uap->op & 0xff0000) >> 16;
98212171Sphk		name[4] = uap->op & 0xff;
98312171Sphk		name[5] = uap->arg;
98412171Sphk		error = userland_sysctl(p, name, 6, uap->where, uap->size,
98512429Sphk			0, 0, 0, &size);
9861541Srgrimes		break;
9871541Srgrimes
9881541Srgrimes	case KINFO_VNODE:
98912171Sphk		name[0] = CTL_KERN;
99012171Sphk		name[1] = KERN_VNODE;
99112171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
99212429Sphk			0, 0, 0, &size);
9931541Srgrimes		break;
9941541Srgrimes
9951541Srgrimes	case KINFO_PROC:
99612171Sphk		name[0] = CTL_KERN;
99712171Sphk		name[1] = KERN_PROC;
99812171Sphk		name[2] = uap->op & 0xff;
99912171Sphk		name[3] = uap->arg;
100012171Sphk		error = userland_sysctl(p, name, 4, uap->where, uap->size,
100112429Sphk			0, 0, 0, &size);
10021541Srgrimes		break;
10031541Srgrimes
10041541Srgrimes	case KINFO_FILE:
100512171Sphk		name[0] = CTL_KERN;
100612171Sphk		name[1] = KERN_FILE;
100712171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
100812429Sphk			0, 0, 0, &size);
10091541Srgrimes		break;
10101541Srgrimes
10111541Srgrimes	case KINFO_METER:
101212171Sphk		name[0] = CTL_VM;
101312171Sphk		name[1] = VM_METER;
101412171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
101512429Sphk			0, 0, 0, &size);
10161541Srgrimes		break;
10171541Srgrimes
10181541Srgrimes	case KINFO_LOADAVG:
101912171Sphk		name[0] = CTL_VM;
102012171Sphk		name[1] = VM_LOADAVG;
102112171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
102212429Sphk			0, 0, 0, &size);
10231541Srgrimes		break;
10241541Srgrimes
10251541Srgrimes	case KINFO_CLOCKRATE:
102612171Sphk		name[0] = CTL_KERN;
102712171Sphk		name[1] = KERN_CLOCKRATE;
102812171Sphk		error = userland_sysctl(p, name, 2, uap->where, uap->size,
102912429Sphk			0, 0, 0, &size);
10301541Srgrimes		break;
10311541Srgrimes
10329455Speter	case KINFO_BSDI_SYSINFO: {
10339455Speter		/*
10349455Speter		 * this is pretty crude, but it's just enough for uname()
10359455Speter		 * from BSDI's 1.x libc to work.
10369455Speter		 *
10379455Speter		 * In particular, it doesn't return the same results when
10389455Speter		 * the supplied buffer is too small.  BSDI's version apparently
10399455Speter		 * will return the amount copied, and set the *size to how
10409455Speter		 * much was needed.  The emulation framework here isn't capable
10419455Speter		 * of that, so we just set both to the amount copied.
10429455Speter		 * BSDI's 2.x product apparently fails with ENOMEM in this
10439455Speter		 * scenario.
10449455Speter		 */
10459455Speter
10469455Speter		u_int needed;
10479455Speter		u_int left;
10489455Speter		char *s;
10499455Speter
10509455Speter		bzero((char *)&bsdi_si, sizeof(bsdi_si));
10519455Speter		bzero(bsdi_strings, sizeof(bsdi_strings));
10529455Speter
10539455Speter		s = bsdi_strings;
10549455Speter
10559455Speter		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
10569455Speter		strcpy(s, ostype);
10579455Speter		s += strlen(s) + 1;
10589455Speter
10599455Speter		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
10609455Speter		strcpy(s, osrelease);
10619455Speter		s += strlen(s) + 1;
10629455Speter
10639455Speter		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
10649455Speter		strcpy(s, machine);
10659455Speter		s += strlen(s) + 1;
10669455Speter
10679455Speter		needed = sizeof(bsdi_si) + (s - bsdi_strings);
10689455Speter
10699455Speter		if (uap->where == NULL) {
10709455Speter			/* process is asking how much buffer to supply.. */
10719455Speter			size = needed;
10729455Speter			error = 0;
10739455Speter			break;
10749455Speter		}
10759455Speter
10769455Speter
10779455Speter		/* if too much buffer supplied, trim it down */
10789455Speter		if (size > needed)
10799455Speter			size = needed;
10809455Speter
10819455Speter		/* how much of the buffer is remaining */
10829455Speter		left = size;
10839455Speter
10849455Speter		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
10859455Speter			break;
10869455Speter
10879455Speter		/* is there any point in continuing? */
10889455Speter		if (left > sizeof(bsdi_si)) {
10899455Speter			left -= sizeof(bsdi_si);
10909455Speter			error = copyout(&bsdi_strings,
10919455Speter					uap->where + sizeof(bsdi_si), left);
10929455Speter		}
10939455Speter		break;
10949455Speter	}
10959455Speter
10961541Srgrimes	default:
10971541Srgrimes		return (EOPNOTSUPP);
10981541Srgrimes	}
10991541Srgrimes	if (error)
11001541Srgrimes		return (error);
110130994Sphk	p->p_retval[0] = size;
11021541Srgrimes	if (uap->size)
11031541Srgrimes		error = copyout((caddr_t)&size, (caddr_t)uap->size,
11041541Srgrimes		    sizeof(size));
11051541Srgrimes	return (error);
11061541Srgrimes}
11071541Srgrimes#endif /* COMPAT_43 */
1108