kern_sysctl.c revision 12243
19663SMark.Logan@Sun.COM/*-
29663SMark.Logan@Sun.COM * Copyright (c) 1982, 1986, 1989, 1993
39663SMark.Logan@Sun.COM *	The Regents of the University of California.  All rights reserved.
49663SMark.Logan@Sun.COM *
59663SMark.Logan@Sun.COM * This code is derived from software contributed to Berkeley by
69663SMark.Logan@Sun.COM * Mike Karels at Berkeley Software Design, Inc.
79663SMark.Logan@Sun.COM *
89663SMark.Logan@Sun.COM * Redistribution and use in source and binary forms, with or without
99663SMark.Logan@Sun.COM * modification, are permitted provided that the following conditions
109663SMark.Logan@Sun.COM * are met:
119663SMark.Logan@Sun.COM * 1. Redistributions of source code must retain the above copyright
129663SMark.Logan@Sun.COM *    notice, this list of conditions and the following disclaimer.
139663SMark.Logan@Sun.COM * 2. Redistributions in binary form must reproduce the above copyright
149663SMark.Logan@Sun.COM *    notice, this list of conditions and the following disclaimer in the
159663SMark.Logan@Sun.COM *    documentation and/or other materials provided with the distribution.
169663SMark.Logan@Sun.COM * 3. All advertising materials mentioning features or use of this software
179663SMark.Logan@Sun.COM *    must display the following acknowledgement:
189663SMark.Logan@Sun.COM *	This product includes software developed by the University of
199663SMark.Logan@Sun.COM *	California, Berkeley and its contributors.
209663SMark.Logan@Sun.COM * 4. Neither the name of the University nor the names of its contributors
219663SMark.Logan@Sun.COM *    may be used to endorse or promote products derived from this software
229663SMark.Logan@Sun.COM *    without specific prior written permission.
239663SMark.Logan@Sun.COM *
249663SMark.Logan@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
259663SMark.Logan@Sun.COM * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
269663SMark.Logan@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
279663SMark.Logan@Sun.COM * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
289663SMark.Logan@Sun.COM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
299663SMark.Logan@Sun.COM * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
309663SMark.Logan@Sun.COM * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
319663SMark.Logan@Sun.COM * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
329663SMark.Logan@Sun.COM * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
339663SMark.Logan@Sun.COM * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
349663SMark.Logan@Sun.COM * SUCH DAMAGE.
359663SMark.Logan@Sun.COM *
369663SMark.Logan@Sun.COM *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
379663SMark.Logan@Sun.COM * $Id: kern_sysctl.c,v 1.37 1995/11/12 06:43:01 bde Exp $
389663SMark.Logan@Sun.COM */
399663SMark.Logan@Sun.COM
409663SMark.Logan@Sun.COM/*
419663SMark.Logan@Sun.COM * sysctl system call.
429663SMark.Logan@Sun.COM */
439663SMark.Logan@Sun.COM
449663SMark.Logan@Sun.COM#include <sys/param.h>
459663SMark.Logan@Sun.COM#include <sys/systm.h>
469663SMark.Logan@Sun.COM#include <sys/sysproto.h>
479663SMark.Logan@Sun.COM#include <sys/kernel.h>
489663SMark.Logan@Sun.COM#include <sys/malloc.h>
499663SMark.Logan@Sun.COM#include <sys/proc.h>
509663SMark.Logan@Sun.COM#include <sys/file.h>
519663SMark.Logan@Sun.COM#include <sys/vnode.h>
529663SMark.Logan@Sun.COM#include <sys/unistd.h>
539663SMark.Logan@Sun.COM#include <sys/buf.h>
549663SMark.Logan@Sun.COM#include <sys/ioctl.h>
559663SMark.Logan@Sun.COM#include <sys/tty.h>
569663SMark.Logan@Sun.COM#include <sys/conf.h>
579663SMark.Logan@Sun.COM#include <vm/vm.h>
589663SMark.Logan@Sun.COM#include <sys/sysctl.h>
599663SMark.Logan@Sun.COM#include <sys/user.h>
6010214SMark.Logan@Sun.COM
619663SMark.Logan@Sun.COMextern struct linker_set sysctl_;
629663SMark.Logan@Sun.COM
639663SMark.Logan@Sun.COM/* BEGIN_MIB */
649663SMark.Logan@Sun.COMSYSCTL_NODE(, 0,	  sysctl, CTLFLAG_RW, 0,
659663SMark.Logan@Sun.COM	"Sysctl internal magic");
669663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_KERN,	  kern,   CTLFLAG_RW, 0,
679663SMark.Logan@Sun.COM	"High kernel, proc, limits &c");
689663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_VM,	  vm,     CTLFLAG_RW, 0,
699663SMark.Logan@Sun.COM	"Virtual memory");
709663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_FS,	  fs,     CTLFLAG_RW, 0,
719663SMark.Logan@Sun.COM	"File system");
729663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_NET,	  net,    CTLFLAG_RW, 0,
739663SMark.Logan@Sun.COM	"Network, (see socket.h)");
749663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_DEBUG,  debug,  CTLFLAG_RW, 0,
759663SMark.Logan@Sun.COM	"Debugging");
769663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_HW,	  hw,     CTLFLAG_RW, 0,
779663SMark.Logan@Sun.COM	"hardware");
789663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0,
799663SMark.Logan@Sun.COM	"machine dependent");
809663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_USER,	  user,   CTLFLAG_RW, 0,
819663SMark.Logan@Sun.COM	"user-level");
829663SMark.Logan@Sun.COM
839663SMark.Logan@Sun.COMSYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, "");
849663SMark.Logan@Sun.COM
859663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, "");
869663SMark.Logan@Sun.COM
879663SMark.Logan@Sun.COMSYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, "");
889663SMark.Logan@Sun.COM
899663SMark.Logan@Sun.COMSYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, "");
909663SMark.Logan@Sun.COM
919663SMark.Logan@Sun.COMextern int osreldate;
929663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, "");
939663SMark.Logan@Sun.COM
949663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, "");
959663SMark.Logan@Sun.COM
969663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, "");
979663SMark.Logan@Sun.COM
989663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid,
999663SMark.Logan@Sun.COM	CTLFLAG_RD, &maxprocperuid, 0, "");
1009663SMark.Logan@Sun.COM
1019663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc,
1029663SMark.Logan@Sun.COM	CTLFLAG_RD, &maxfilesperproc, 0, "");
1039663SMark.Logan@Sun.COM
1049663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, "");
1059663SMark.Logan@Sun.COM
1069663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, "");
1079663SMark.Logan@Sun.COM
1089663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, "");
1099663SMark.Logan@Sun.COM
1109663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, "");
1119663SMark.Logan@Sun.COM
1129663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, "");
1139663SMark.Logan@Sun.COM
1149663SMark.Logan@Sun.COM#ifdef _POSIX_SAVED_IDS
1159663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, "");
1169663SMark.Logan@Sun.COM#else
1179663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, "");
1189663SMark.Logan@Sun.COM#endif
1199663SMark.Logan@Sun.COM
1209663SMark.Logan@Sun.COMchar kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
1219663SMark.Logan@Sun.COM
1229663SMark.Logan@Sun.COMSYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile,
1239663SMark.Logan@Sun.COM	CTLFLAG_RW, kernelname, sizeof kernelname, "");
1249663SMark.Logan@Sun.COM
1259663SMark.Logan@Sun.COMSYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime,
1269663SMark.Logan@Sun.COM	CTLFLAG_RW, &boottime, timeval, "");
1279663SMark.Logan@Sun.COM
1289663SMark.Logan@Sun.COMSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
1299663SMark.Logan@Sun.COM
1309663SMark.Logan@Sun.COMSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "");
1319663SMark.Logan@Sun.COM
1329663SMark.Logan@Sun.COMSYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, "");
1339663SMark.Logan@Sun.COM
1349663SMark.Logan@Sun.COMSYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, "");
1359663SMark.Logan@Sun.COM
1369663SMark.Logan@Sun.COMSYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, "");
1379663SMark.Logan@Sun.COM
1389663SMark.Logan@Sun.COM/* END_MIB */
1399663SMark.Logan@Sun.COM
1409663SMark.Logan@Sun.COMextern int vfs_update_wakeup;
1419663SMark.Logan@Sun.COMextern int vfs_update_interval;
1429663SMark.Logan@Sun.COMstatic int
1439663SMark.Logan@Sun.COMsysctl_kern_updateinterval SYSCTL_HANDLER_ARGS
1449663SMark.Logan@Sun.COM{
1459663SMark.Logan@Sun.COM	int error = sysctl_handle_int(oidp,
1469663SMark.Logan@Sun.COM		oidp->oid_arg1, oidp->oid_arg2, req);
1479663SMark.Logan@Sun.COM	if (!error)
1489663SMark.Logan@Sun.COM		wakeup(&vfs_update_wakeup);
1499663SMark.Logan@Sun.COM	return error;
1509663SMark.Logan@Sun.COM}
1519663SMark.Logan@Sun.COM
1529663SMark.Logan@Sun.COMSYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW,
1539663SMark.Logan@Sun.COM	&vfs_update_interval, 0, sysctl_kern_updateinterval, "");
1549663SMark.Logan@Sun.COM
1559663SMark.Logan@Sun.COM
1569663SMark.Logan@Sun.COMchar hostname[MAXHOSTNAMELEN];
1579663SMark.Logan@Sun.COMint hostnamelen;
1589663SMark.Logan@Sun.COMstatic int
1599663SMark.Logan@Sun.COMsysctl_kern_hostname SYSCTL_HANDLER_ARGS
1609663SMark.Logan@Sun.COM{
1619663SMark.Logan@Sun.COM	int error = sysctl_handle_string(oidp,
1629663SMark.Logan@Sun.COM		oidp->oid_arg1, oidp->oid_arg2, req);
1639663SMark.Logan@Sun.COM	if (req->newptr && (error == 0 || error == ENOMEM))
1649663SMark.Logan@Sun.COM		hostnamelen = req->newlen;
1659663SMark.Logan@Sun.COM	return error;
1669663SMark.Logan@Sun.COM}
1679663SMark.Logan@Sun.COM
1689663SMark.Logan@Sun.COMSYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW,
1699663SMark.Logan@Sun.COM	&hostname, sizeof(hostname), sysctl_kern_hostname, "");
1709663SMark.Logan@Sun.COM
1719663SMark.Logan@Sun.COMstatic int
1729663SMark.Logan@Sun.COMsysctl_order_cmp(const void *a, const void *b)
1739663SMark.Logan@Sun.COM{
1749663SMark.Logan@Sun.COM	const struct sysctl_oid **pa, **pb;
1759663SMark.Logan@Sun.COM
1769663SMark.Logan@Sun.COM	pa = (const struct sysctl_oid **)a;
1779663SMark.Logan@Sun.COM	pb = (const struct sysctl_oid **)b;
1789663SMark.Logan@Sun.COM	if (*pa == NULL)
1799663SMark.Logan@Sun.COM		return (1);
1809663SMark.Logan@Sun.COM	if (*pb == NULL)
1819663SMark.Logan@Sun.COM		return (-1);
1829663SMark.Logan@Sun.COM	return ((*pa)->oid_number - (*pb)->oid_number);
1839663SMark.Logan@Sun.COM}
1849663SMark.Logan@Sun.COM
1859663SMark.Logan@Sun.COMstatic void
1869663SMark.Logan@Sun.COMsysctl_order(void *arg)
1879663SMark.Logan@Sun.COM{
1889663SMark.Logan@Sun.COM	int j;
1899663SMark.Logan@Sun.COM	struct linker_set *l = (struct linker_set *) arg;
1909663SMark.Logan@Sun.COM	struct sysctl_oid **oidpp;
1919663SMark.Logan@Sun.COM
1929663SMark.Logan@Sun.COM	j = l->ls_length;
1939663SMark.Logan@Sun.COM	oidpp = (struct sysctl_oid **) l->ls_items;
1949663SMark.Logan@Sun.COM	for (; j--; oidpp++) {
1959663SMark.Logan@Sun.COM		if (!*oidpp)
1969663SMark.Logan@Sun.COM			continue;
1979663SMark.Logan@Sun.COM		if ((*oidpp)->oid_arg1 == arg) {
1989663SMark.Logan@Sun.COM			*oidpp = 0;
1999663SMark.Logan@Sun.COM			continue;
2009663SMark.Logan@Sun.COM		}
2019663SMark.Logan@Sun.COM		if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
2029663SMark.Logan@Sun.COM			if (!(*oidpp)->oid_handler)
2039663SMark.Logan@Sun.COM				sysctl_order((*oidpp)->oid_arg1);
2049663SMark.Logan@Sun.COM	}
2059663SMark.Logan@Sun.COM	qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
2069663SMark.Logan@Sun.COM		sysctl_order_cmp);
2079663SMark.Logan@Sun.COM}
2089663SMark.Logan@Sun.COM
2099663SMark.Logan@Sun.COMSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
2109663SMark.Logan@Sun.COM
2119663SMark.Logan@Sun.COMstatic void
2129663SMark.Logan@Sun.COMsysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
2139663SMark.Logan@Sun.COM{
2149663SMark.Logan@Sun.COM	int j, k;
2159663SMark.Logan@Sun.COM	struct sysctl_oid **oidpp;
2169663SMark.Logan@Sun.COM
2179663SMark.Logan@Sun.COM	j = l->ls_length;
2189663SMark.Logan@Sun.COM	oidpp = (struct sysctl_oid **) l->ls_items;
2199663SMark.Logan@Sun.COM	for (; j--; oidpp++) {
2209663SMark.Logan@Sun.COM
2219663SMark.Logan@Sun.COM		if (!*oidpp)
2229663SMark.Logan@Sun.COM			continue;
2239663SMark.Logan@Sun.COM
2249663SMark.Logan@Sun.COM		for (k=0; k<i; k++)
2259663SMark.Logan@Sun.COM			printf(" ");
2269663SMark.Logan@Sun.COM
2279663SMark.Logan@Sun.COM		if ((*oidpp)->oid_number > 100) {
2289663SMark.Logan@Sun.COM			printf("Junk! %p  # %d  %s  k %x  a1 %p  a2 %x  h %p\n",
2299663SMark.Logan@Sun.COM				*oidpp,
2309663SMark.Logan@Sun.COM		 		(*oidpp)->oid_number, (*oidpp)->oid_name,
2319663SMark.Logan@Sun.COM		 		(*oidpp)->oid_kind, (*oidpp)->oid_arg1,
2329663SMark.Logan@Sun.COM		 		(*oidpp)->oid_arg2, (*oidpp)->oid_handler);
2339663SMark.Logan@Sun.COM			continue;
2349663SMark.Logan@Sun.COM		}
2359663SMark.Logan@Sun.COM		printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
2369663SMark.Logan@Sun.COM
2379663SMark.Logan@Sun.COM		printf("%c%c",
2389663SMark.Logan@Sun.COM			(*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
2399663SMark.Logan@Sun.COM			(*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
2409663SMark.Logan@Sun.COM
2419663SMark.Logan@Sun.COM		switch ((*oidpp)->oid_kind & CTLTYPE) {
2429663SMark.Logan@Sun.COM			case CTLTYPE_NODE:
2439663SMark.Logan@Sun.COM				if ((*oidpp)->oid_handler) {
2449663SMark.Logan@Sun.COM					printf(" Node(proc)\n");
2459663SMark.Logan@Sun.COM				} else {
2469663SMark.Logan@Sun.COM					printf(" Node\n");
2479663SMark.Logan@Sun.COM					sysctl_sysctl_debug_dump_node(
2489663SMark.Logan@Sun.COM						(*oidpp)->oid_arg1, i+2);
2499663SMark.Logan@Sun.COM				}
2509663SMark.Logan@Sun.COM				break;
2519663SMark.Logan@Sun.COM			case CTLTYPE_INT:    printf(" Int\n"); break;
2529663SMark.Logan@Sun.COM			case CTLTYPE_STRING: printf(" String\n"); break;
2539663SMark.Logan@Sun.COM			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
2549663SMark.Logan@Sun.COM			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
2559663SMark.Logan@Sun.COM			default:	     printf("\n");
2569663SMark.Logan@Sun.COM		}
2579663SMark.Logan@Sun.COM
2589663SMark.Logan@Sun.COM	}
2599663SMark.Logan@Sun.COM}
2609663SMark.Logan@Sun.COM
2619663SMark.Logan@Sun.COM
2629663SMark.Logan@Sun.COMstatic int
2639663SMark.Logan@Sun.COMsysctl_sysctl_debug SYSCTL_HANDLER_ARGS
2649663SMark.Logan@Sun.COM{
2659663SMark.Logan@Sun.COM	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
2669663SMark.Logan@Sun.COM	return ENOENT;
2679663SMark.Logan@Sun.COM}
2689663SMark.Logan@Sun.COM
2699663SMark.Logan@Sun.COMSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
2709663SMark.Logan@Sun.COM	0, 0, sysctl_sysctl_debug, "");
2719663SMark.Logan@Sun.COM
2729663SMark.Logan@Sun.COMchar domainname[MAXHOSTNAMELEN];
2739663SMark.Logan@Sun.COMint domainnamelen;
2749663SMark.Logan@Sun.COMstatic int
2759663SMark.Logan@Sun.COMsysctl_kern_domainname SYSCTL_HANDLER_ARGS
2769663SMark.Logan@Sun.COM{
2779663SMark.Logan@Sun.COM	int error = sysctl_handle_string(oidp,
2789663SMark.Logan@Sun.COM		oidp->oid_arg1, oidp->oid_arg2, req);
2799663SMark.Logan@Sun.COM	if (req->newptr && (error == 0 || error == ENOMEM))
2809663SMark.Logan@Sun.COM		domainnamelen = req->newlen;
2819663SMark.Logan@Sun.COM	return error;
2829663SMark.Logan@Sun.COM}
2839663SMark.Logan@Sun.COM
2849663SMark.Logan@Sun.COMSYSCTL_PROC(_kern, KERN_DOMAINNAME, domainname, CTLTYPE_STRING|CTLFLAG_RW,
2859663SMark.Logan@Sun.COM	&domainname, sizeof(domainname), sysctl_kern_domainname, "");
2869663SMark.Logan@Sun.COM
2879663SMark.Logan@Sun.COMlong hostid;
2889663SMark.Logan@Sun.COM/* Some trouble here, if sizeof (int) != sizeof (long) */
2899663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, "");
2909663SMark.Logan@Sun.COM
2919663SMark.Logan@Sun.COM/*
2929663SMark.Logan@Sun.COM * Handle an integer, signed or unsigned.
2939663SMark.Logan@Sun.COM * Two cases:
2949663SMark.Logan@Sun.COM *     a variable:  point arg1 at it.
2959663SMark.Logan@Sun.COM *     a constant:  pass it in arg2.
2969663SMark.Logan@Sun.COM */
2979663SMark.Logan@Sun.COM
2989663SMark.Logan@Sun.COMint
2999663SMark.Logan@Sun.COMsysctl_handle_int SYSCTL_HANDLER_ARGS
3009663SMark.Logan@Sun.COM{
3019663SMark.Logan@Sun.COM	int error = 0;
3029663SMark.Logan@Sun.COM
3039663SMark.Logan@Sun.COM	if (arg1)
3049663SMark.Logan@Sun.COM		error = SYSCTL_OUT(req, arg1, sizeof(int));
3059663SMark.Logan@Sun.COM	else if (arg2)
3069663SMark.Logan@Sun.COM		error = SYSCTL_OUT(req, &arg2, sizeof(int));
3079663SMark.Logan@Sun.COM
3089663SMark.Logan@Sun.COM	if (error || !req->newptr)
3099663SMark.Logan@Sun.COM		return (error);
3109663SMark.Logan@Sun.COM
3119663SMark.Logan@Sun.COM	if (!arg1)
3129663SMark.Logan@Sun.COM		error = EPERM;
3139663SMark.Logan@Sun.COM	else
3149663SMark.Logan@Sun.COM		error = SYSCTL_IN(req, arg1, sizeof(int));
3159663SMark.Logan@Sun.COM	return (error);
3169663SMark.Logan@Sun.COM}
3179663SMark.Logan@Sun.COM
3189663SMark.Logan@Sun.COM/*
3199663SMark.Logan@Sun.COM * Handle our generic '\0' terminated 'C' string.
3209663SMark.Logan@Sun.COM * Two cases:
3219663SMark.Logan@Sun.COM * 	a variable string:  point arg1 at it, arg2 is max length.
3229663SMark.Logan@Sun.COM * 	a constant string:  point arg1 at it, arg2 is zero.
3239663SMark.Logan@Sun.COM */
3249663SMark.Logan@Sun.COM
3259663SMark.Logan@Sun.COMint
3269663SMark.Logan@Sun.COMsysctl_handle_string SYSCTL_HANDLER_ARGS
3279663SMark.Logan@Sun.COM{
3289663SMark.Logan@Sun.COM	int error=0;
3299663SMark.Logan@Sun.COM
3309663SMark.Logan@Sun.COM	if (arg2)
3319663SMark.Logan@Sun.COM		error = SYSCTL_OUT(req, arg1, arg2);
3329663SMark.Logan@Sun.COM	else
3339663SMark.Logan@Sun.COM		error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
3349663SMark.Logan@Sun.COM
3359663SMark.Logan@Sun.COM	if (error || !req->newptr)
3369663SMark.Logan@Sun.COM		return (error);
3379663SMark.Logan@Sun.COM
3389663SMark.Logan@Sun.COM	if ((req->newlen - req->newidx) > arg2) {
3399663SMark.Logan@Sun.COM		error = E2BIG;
3409663SMark.Logan@Sun.COM	} else {
3419663SMark.Logan@Sun.COM		arg2 = (req->newlen - req->newidx);
3429663SMark.Logan@Sun.COM		error = SYSCTL_IN(req, arg1, arg2);
3439663SMark.Logan@Sun.COM		((char *)arg1)[arg2] = '\0';
3449663SMark.Logan@Sun.COM	}
3459663SMark.Logan@Sun.COM
3469663SMark.Logan@Sun.COM	return (error);
3479663SMark.Logan@Sun.COM}
3489663SMark.Logan@Sun.COM
3499663SMark.Logan@Sun.COM/*
3509663SMark.Logan@Sun.COM * Handle any kind of opaque data.
3519663SMark.Logan@Sun.COM * arg1 points to it, arg2 is the size.
3529663SMark.Logan@Sun.COM */
3539663SMark.Logan@Sun.COM
3549663SMark.Logan@Sun.COMint
3559663SMark.Logan@Sun.COMsysctl_handle_opaque SYSCTL_HANDLER_ARGS
3569663SMark.Logan@Sun.COM{
3579663SMark.Logan@Sun.COM	int error;
3589663SMark.Logan@Sun.COM
3599663SMark.Logan@Sun.COM	error = SYSCTL_OUT(req, arg1, arg2);
3609663SMark.Logan@Sun.COM
3619663SMark.Logan@Sun.COM	if (error || !req->newptr)
3629663SMark.Logan@Sun.COM		return (error);
3639663SMark.Logan@Sun.COM
3649663SMark.Logan@Sun.COM	error = SYSCTL_IN(req, arg1, arg2);
3659663SMark.Logan@Sun.COM
3669663SMark.Logan@Sun.COM	return (error);
3679663SMark.Logan@Sun.COM}
3689663SMark.Logan@Sun.COM
3699663SMark.Logan@Sun.COMint
3709663SMark.Logan@Sun.COMsysctl_old_kernel(struct sysctl_req *req, void *p, int l)
3719663SMark.Logan@Sun.COM{
3729663SMark.Logan@Sun.COM	int i = min(req->oldlen - req->oldidx, l);
3739663SMark.Logan@Sun.COM	if (i) {
3749663SMark.Logan@Sun.COM		bcopy(p, req->oldptr + req->oldidx, i);
3759663SMark.Logan@Sun.COM		req->oldidx += i;
3769663SMark.Logan@Sun.COM	}
3779663SMark.Logan@Sun.COM	if (i != l)
3789663SMark.Logan@Sun.COM		return (ENOMEM);
3799663SMark.Logan@Sun.COM	else
3809663SMark.Logan@Sun.COM		return (0);
3819663SMark.Logan@Sun.COM
3829663SMark.Logan@Sun.COM}
3839663SMark.Logan@Sun.COM
3849663SMark.Logan@Sun.COMint
3859663SMark.Logan@Sun.COMsysctl_new_kernel(struct sysctl_req *req, void *p, int l)
3869663SMark.Logan@Sun.COM{
3879663SMark.Logan@Sun.COM	int i = req->newlen - req->newidx;
3889663SMark.Logan@Sun.COM	if (i < l)
3899663SMark.Logan@Sun.COM		return (EINVAL);
3909663SMark.Logan@Sun.COM	bcopy(req->newptr + req->newidx, p, l);
3919663SMark.Logan@Sun.COM	req->newidx += l;
3929663SMark.Logan@Sun.COM	return (0);
3939663SMark.Logan@Sun.COM}
3949663SMark.Logan@Sun.COM
3959663SMark.Logan@Sun.COMint
3969663SMark.Logan@Sun.COMsysctl_old_user(struct sysctl_req *req, void *p, int l)
3979663SMark.Logan@Sun.COM{
3989663SMark.Logan@Sun.COM	int error , i = min(req->oldlen - req->oldidx, l);
3999663SMark.Logan@Sun.COM
4009663SMark.Logan@Sun.COM	error  = copyout(p, req->oldptr + req->oldidx, i);
4019663SMark.Logan@Sun.COM	req->oldidx += i;
4029663SMark.Logan@Sun.COM	if (error)
4039663SMark.Logan@Sun.COM		return (error);
4049663SMark.Logan@Sun.COM	if (i < l)
4059663SMark.Logan@Sun.COM		return (ENOMEM);
4069663SMark.Logan@Sun.COM	return (error);
4079663SMark.Logan@Sun.COM}
4089663SMark.Logan@Sun.COM
4099663SMark.Logan@Sun.COMint
4109663SMark.Logan@Sun.COMsysctl_new_user(struct sysctl_req *req, void *p, int l)
4119663SMark.Logan@Sun.COM{
4129663SMark.Logan@Sun.COM	int error, i = req->newlen - req->newidx;
4139663SMark.Logan@Sun.COM	if (i < l)
4149663SMark.Logan@Sun.COM		return (EINVAL);
4159663SMark.Logan@Sun.COM	error = copyin(req->newptr + req->newidx, p, l);
4169663SMark.Logan@Sun.COM	req->newidx += l;
4179663SMark.Logan@Sun.COM	return (error);
4189663SMark.Logan@Sun.COM}
4199663SMark.Logan@Sun.COM
4209663SMark.Logan@Sun.COM#ifdef DEBUG
4219663SMark.Logan@Sun.COMstatic sysctlfn debug_sysctl;
4229663SMark.Logan@Sun.COM#endif
4239663SMark.Logan@Sun.COM
4249663SMark.Logan@Sun.COM/*
4259663SMark.Logan@Sun.COM * Locking and stats
4269663SMark.Logan@Sun.COM */
4279663SMark.Logan@Sun.COMstatic struct sysctl_lock {
4289663SMark.Logan@Sun.COM	int	sl_lock;
4299663SMark.Logan@Sun.COM	int	sl_want;
4309663SMark.Logan@Sun.COM	int	sl_locked;
4319663SMark.Logan@Sun.COM} memlock;
4329663SMark.Logan@Sun.COM
4339663SMark.Logan@Sun.COM
4349663SMark.Logan@Sun.COM
4359663SMark.Logan@Sun.COM/*
4369663SMark.Logan@Sun.COM * Traverse our tree, and find the right node, execute whatever it points
4379663SMark.Logan@Sun.COM * at, and return the resulting error code.
4389663SMark.Logan@Sun.COM * We work entirely in kernel-space at this time.
4399663SMark.Logan@Sun.COM */
4409663SMark.Logan@Sun.COM
4419663SMark.Logan@Sun.COM
4429663SMark.Logan@Sun.COMint
4439663SMark.Logan@Sun.COMsysctl_root SYSCTL_HANDLER_ARGS
4449663SMark.Logan@Sun.COM{
4459663SMark.Logan@Sun.COM	int *name = (int *) arg1;
4469663SMark.Logan@Sun.COM	int namelen = arg2;
4479663SMark.Logan@Sun.COM	int indx, i, j;
4489663SMark.Logan@Sun.COM	struct sysctl_oid **oidpp;
4499663SMark.Logan@Sun.COM	struct linker_set *lsp = &sysctl_;
4509663SMark.Logan@Sun.COM
4519663SMark.Logan@Sun.COM	j = lsp->ls_length;
4529663SMark.Logan@Sun.COM	oidpp = (struct sysctl_oid **) lsp->ls_items;
4539663SMark.Logan@Sun.COM
4549663SMark.Logan@Sun.COM	indx = 0;
4559663SMark.Logan@Sun.COM	while (j-- && indx < CTL_MAXNAME) {
4569663SMark.Logan@Sun.COM		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
4579663SMark.Logan@Sun.COM			indx++;
4589663SMark.Logan@Sun.COM			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
4599663SMark.Logan@Sun.COM				if ((*oidpp)->oid_handler)
4609663SMark.Logan@Sun.COM					goto found;
4619663SMark.Logan@Sun.COM				if (indx == namelen)
4629663SMark.Logan@Sun.COM					return ENOENT;
4639663SMark.Logan@Sun.COM				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
4649663SMark.Logan@Sun.COM				j = lsp->ls_length;
4659663SMark.Logan@Sun.COM				oidpp = (struct sysctl_oid **)lsp->ls_items;
4669663SMark.Logan@Sun.COM			} else {
4679663SMark.Logan@Sun.COM				if (indx != namelen)
4689663SMark.Logan@Sun.COM					return EISDIR;
4699663SMark.Logan@Sun.COM				goto found;
4709663SMark.Logan@Sun.COM			}
4719663SMark.Logan@Sun.COM		} else {
4729663SMark.Logan@Sun.COM			oidpp++;
4739663SMark.Logan@Sun.COM		}
4749663SMark.Logan@Sun.COM	}
4759663SMark.Logan@Sun.COM	return EJUSTRETURN;
4769663SMark.Logan@Sun.COMfound:
4779663SMark.Logan@Sun.COM
4789663SMark.Logan@Sun.COM	/* If writing isn't allowed */
4799663SMark.Logan@Sun.COM	if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR))
4809663SMark.Logan@Sun.COM		return (EPERM);
4819663SMark.Logan@Sun.COM
4829663SMark.Logan@Sun.COM	if (!(*oidpp)->oid_handler)
4839663SMark.Logan@Sun.COM		return EINVAL;
4849663SMark.Logan@Sun.COM
4859663SMark.Logan@Sun.COM	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
4869663SMark.Logan@Sun.COM		i = ((*oidpp)->oid_handler) (*oidpp,
4879663SMark.Logan@Sun.COM					name + indx, namelen - indx,
4889663SMark.Logan@Sun.COM					req);
4899663SMark.Logan@Sun.COM	} else {
4909663SMark.Logan@Sun.COM		i = ((*oidpp)->oid_handler) (*oidpp,
4919663SMark.Logan@Sun.COM					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
4929663SMark.Logan@Sun.COM					req);
4939663SMark.Logan@Sun.COM	}
4949663SMark.Logan@Sun.COM	return (i);
4959663SMark.Logan@Sun.COM}
4969663SMark.Logan@Sun.COM
4979663SMark.Logan@Sun.COM#ifndef _SYS_SYSPROTO_H_
4989663SMark.Logan@Sun.COMstruct sysctl_args {
4999663SMark.Logan@Sun.COM	int	*name;
5009663SMark.Logan@Sun.COM	u_int	namelen;
5019663SMark.Logan@Sun.COM	void	*old;
5029663SMark.Logan@Sun.COM	size_t	*oldlenp;
5039663SMark.Logan@Sun.COM	void	*new;
5049663SMark.Logan@Sun.COM	size_t	newlen;
5059663SMark.Logan@Sun.COM};
5069663SMark.Logan@Sun.COM#endif
5079663SMark.Logan@Sun.COM
5089663SMark.Logan@Sun.COMint
5099663SMark.Logan@Sun.COM__sysctl(p, uap, retval)
5109663SMark.Logan@Sun.COM	struct proc *p;
5119663SMark.Logan@Sun.COM	register struct sysctl_args *uap;
5129663SMark.Logan@Sun.COM	int *retval;
5139663SMark.Logan@Sun.COM{
5149663SMark.Logan@Sun.COM	int error, name[CTL_MAXNAME];
5159663SMark.Logan@Sun.COM
5169663SMark.Logan@Sun.COM	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
5179663SMark.Logan@Sun.COM		return (EINVAL);
5189663SMark.Logan@Sun.COM
5199663SMark.Logan@Sun.COM 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
5209663SMark.Logan@Sun.COM 	if (error)
5219663SMark.Logan@Sun.COM		return (error);
5229663SMark.Logan@Sun.COM
5239663SMark.Logan@Sun.COM	return (userland_sysctl(p, name, uap->namelen,
5249663SMark.Logan@Sun.COM		uap->old, uap->oldlenp, 0,
5259663SMark.Logan@Sun.COM		uap->new, uap->newlen, retval));
5269663SMark.Logan@Sun.COM}
5279663SMark.Logan@Sun.COM
5289663SMark.Logan@Sun.COMstatic sysctlfn kern_sysctl;
5299663SMark.Logan@Sun.COM
5309663SMark.Logan@Sun.COM/*
5319663SMark.Logan@Sun.COM * This is used from various compatibility syscalls too.  That's why name
5329663SMark.Logan@Sun.COM * must be in kernel space.
5339663SMark.Logan@Sun.COM */
5349663SMark.Logan@Sun.COMint
5359663SMark.Logan@Sun.COMuserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval)
5369663SMark.Logan@Sun.COM{
5379663SMark.Logan@Sun.COM	int error = 0, dolock = 1, i, oldlen = 0;
5389663SMark.Logan@Sun.COM	u_int savelen = 0;
5399663SMark.Logan@Sun.COM	sysctlfn *fn;
5409663SMark.Logan@Sun.COM	struct sysctl_req req;
5419663SMark.Logan@Sun.COM
5429663SMark.Logan@Sun.COM	bzero(&req, sizeof req);
5439663SMark.Logan@Sun.COM
5449663SMark.Logan@Sun.COM	if (new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
5459663SMark.Logan@Sun.COM		return (error);
5469663SMark.Logan@Sun.COM
5479663SMark.Logan@Sun.COM	if (oldlenp) {
5489663SMark.Logan@Sun.COM		if (inkernel) {
5499663SMark.Logan@Sun.COM			req.oldlen = *oldlenp;
5509663SMark.Logan@Sun.COM		} else {
5519663SMark.Logan@Sun.COM			error = copyin(oldlenp, &req.oldlen,
5529663SMark.Logan@Sun.COM				sizeof(req.oldlen));
5539663SMark.Logan@Sun.COM			if (error)
5549663SMark.Logan@Sun.COM				return (error);
5559663SMark.Logan@Sun.COM		}
5569663SMark.Logan@Sun.COM		oldlen = req.oldlen;
5579663SMark.Logan@Sun.COM	}
5589663SMark.Logan@Sun.COM
5599663SMark.Logan@Sun.COM	if (old) {
5609663SMark.Logan@Sun.COM		if (!useracc(old, req.oldlen, B_WRITE))
5619663SMark.Logan@Sun.COM			return (EFAULT);
5629663SMark.Logan@Sun.COM		req.oldptr= old;
5639663SMark.Logan@Sun.COM	}
5649663SMark.Logan@Sun.COM
5659663SMark.Logan@Sun.COM	if (newlen) {
5669663SMark.Logan@Sun.COM		if (!useracc(new, req.newlen, B_READ))
5679663SMark.Logan@Sun.COM			return (EFAULT);
5689663SMark.Logan@Sun.COM		req.newlen = newlen;
5699663SMark.Logan@Sun.COM		req.newptr = new;
5709663SMark.Logan@Sun.COM	}
5719663SMark.Logan@Sun.COM
5729663SMark.Logan@Sun.COM	req.oldfunc = sysctl_old_user;
5739663SMark.Logan@Sun.COM	req.newfunc = sysctl_new_user;
5749663SMark.Logan@Sun.COM
5759663SMark.Logan@Sun.COM	error = sysctl_root(0, name, namelen, &req);
5769663SMark.Logan@Sun.COM
5779663SMark.Logan@Sun.COM        if (!error || error == ENOMEM) {
5789663SMark.Logan@Sun.COM		if (retval)
5799663SMark.Logan@Sun.COM			*retval = req.oldlen;
5809663SMark.Logan@Sun.COM		if (oldlenp) {
5819663SMark.Logan@Sun.COM			if (inkernel) {
5829663SMark.Logan@Sun.COM				*oldlenp = req.oldlen;
5839663SMark.Logan@Sun.COM			} else {
5849663SMark.Logan@Sun.COM				i = copyout(&req.oldlen, oldlenp,
5859663SMark.Logan@Sun.COM					sizeof(req.oldlen));
5869663SMark.Logan@Sun.COM				if (i)
5879663SMark.Logan@Sun.COM					error = i;
5889663SMark.Logan@Sun.COM			}
5899663SMark.Logan@Sun.COM		}
5909663SMark.Logan@Sun.COM		return (error);
5919663SMark.Logan@Sun.COM	}
5929663SMark.Logan@Sun.COM
5939663SMark.Logan@Sun.COM	switch (name[0]) {
5949663SMark.Logan@Sun.COM	case CTL_KERN:
5959663SMark.Logan@Sun.COM		fn = kern_sysctl;
5969663SMark.Logan@Sun.COM		if (name[1] != KERN_VNODE)      /* XXX */
5979663SMark.Logan@Sun.COM			dolock = 0;
5989663SMark.Logan@Sun.COM		break;
5999663SMark.Logan@Sun.COM	case CTL_HW:
6009663SMark.Logan@Sun.COM		fn = hw_sysctl;
6019663SMark.Logan@Sun.COM		break;
6029663SMark.Logan@Sun.COM	case CTL_VM:
6039663SMark.Logan@Sun.COM		fn = vm_sysctl;
6049663SMark.Logan@Sun.COM		break;
6059663SMark.Logan@Sun.COM	case CTL_NET:
6069663SMark.Logan@Sun.COM		fn = net_sysctl;
6079663SMark.Logan@Sun.COM		break;
6089663SMark.Logan@Sun.COM	case CTL_FS:
6099663SMark.Logan@Sun.COM		fn = fs_sysctl;
6109663SMark.Logan@Sun.COM		break;
6119663SMark.Logan@Sun.COM#ifdef DEBUG
6129663SMark.Logan@Sun.COM	case CTL_DEBUG:
6139663SMark.Logan@Sun.COM		fn = debug_sysctl;
6149663SMark.Logan@Sun.COM		break;
6159663SMark.Logan@Sun.COM#endif
6169663SMark.Logan@Sun.COM	default:
6179663SMark.Logan@Sun.COM		return (EOPNOTSUPP);
6189663SMark.Logan@Sun.COM	}
6199663SMark.Logan@Sun.COM	if (old != NULL) {
6209663SMark.Logan@Sun.COM		if (!useracc(old, oldlen, B_WRITE))
6219663SMark.Logan@Sun.COM			return (EFAULT);
6229663SMark.Logan@Sun.COM		while (memlock.sl_lock) {
6239663SMark.Logan@Sun.COM			memlock.sl_want = 1;
6249663SMark.Logan@Sun.COM			(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
6259663SMark.Logan@Sun.COM			memlock.sl_locked++;
6269663SMark.Logan@Sun.COM		}
6279663SMark.Logan@Sun.COM		memlock.sl_lock = 1;
6289663SMark.Logan@Sun.COM		if (dolock)
6299663SMark.Logan@Sun.COM			vslock(old, oldlen);
6309663SMark.Logan@Sun.COM		savelen = oldlen;
6319663SMark.Logan@Sun.COM	}
6329663SMark.Logan@Sun.COM
6339663SMark.Logan@Sun.COM
6349663SMark.Logan@Sun.COM	error = (*fn)(name + 1, namelen - 1, old, &oldlen,
6359663SMark.Logan@Sun.COM	    new, newlen, p);
6369663SMark.Logan@Sun.COM
6379663SMark.Logan@Sun.COM
6389663SMark.Logan@Sun.COM	if (old != NULL) {
6399663SMark.Logan@Sun.COM		if (dolock)
6409663SMark.Logan@Sun.COM			vsunlock(old, savelen, B_WRITE);
6419663SMark.Logan@Sun.COM		memlock.sl_lock = 0;
6429663SMark.Logan@Sun.COM		if (memlock.sl_want) {
6439663SMark.Logan@Sun.COM			memlock.sl_want = 0;
6449663SMark.Logan@Sun.COM			wakeup((caddr_t)&memlock);
6459663SMark.Logan@Sun.COM		}
6469663SMark.Logan@Sun.COM	}
6479663SMark.Logan@Sun.COM#if 0
6489663SMark.Logan@Sun.COM	if (error) {
6499663SMark.Logan@Sun.COM		printf("SYSCTL_ERROR: ");
6509663SMark.Logan@Sun.COM		for(i=0;i<namelen;i++)
6519663SMark.Logan@Sun.COM			printf("%d ", name[i]);
6529663SMark.Logan@Sun.COM		printf("= %d\n", error);
6539663SMark.Logan@Sun.COM	}
6549663SMark.Logan@Sun.COM#endif
6559663SMark.Logan@Sun.COM	if (error)
6569663SMark.Logan@Sun.COM		return (error);
6579663SMark.Logan@Sun.COM	if (retval)
6589663SMark.Logan@Sun.COM		*retval = oldlen;
6599663SMark.Logan@Sun.COM	if (oldlenp) {
6609663SMark.Logan@Sun.COM		if (inkernel) {
6619663SMark.Logan@Sun.COM			*oldlenp = oldlen;
6629663SMark.Logan@Sun.COM		} else {
6639663SMark.Logan@Sun.COM			error = copyout(&oldlen, oldlenp, sizeof(oldlen));
6649663SMark.Logan@Sun.COM		}
6659663SMark.Logan@Sun.COM	}
6669663SMark.Logan@Sun.COM	return (error);
6679663SMark.Logan@Sun.COM}
6689663SMark.Logan@Sun.COM
6699663SMark.Logan@Sun.COM/*
6709663SMark.Logan@Sun.COM * Attributes stored in the kernel.
6719663SMark.Logan@Sun.COM */
6729663SMark.Logan@Sun.COMint securelevel = -1;
6739663SMark.Logan@Sun.COM
6749663SMark.Logan@Sun.COM/*
6759663SMark.Logan@Sun.COM * kernel related system variables.
6769663SMark.Logan@Sun.COM */
6779663SMark.Logan@Sun.COMstatic int
6789663SMark.Logan@Sun.COMkern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
6799663SMark.Logan@Sun.COM	int *name;
6809663SMark.Logan@Sun.COM	u_int namelen;
6819663SMark.Logan@Sun.COM	void *oldp;
6829663SMark.Logan@Sun.COM	size_t *oldlenp;
6839663SMark.Logan@Sun.COM	void *newp;
6849663SMark.Logan@Sun.COM	size_t newlen;
6859663SMark.Logan@Sun.COM	struct proc *p;
6869663SMark.Logan@Sun.COM{
6879663SMark.Logan@Sun.COM	int error, level;
6889663SMark.Logan@Sun.COM	dev_t ndumpdev;
6899663SMark.Logan@Sun.COM
6909663SMark.Logan@Sun.COM	/* all sysctl names at this level are terminal */
6919663SMark.Logan@Sun.COM	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
6929663SMark.Logan@Sun.COM			      || name[0] == KERN_NTP_PLL))
6939663SMark.Logan@Sun.COM		return (ENOTDIR);		/* overloaded */
6949663SMark.Logan@Sun.COM
6959663SMark.Logan@Sun.COM	switch (name[0]) {
6969663SMark.Logan@Sun.COM
6979663SMark.Logan@Sun.COM	case KERN_SECURELVL:
6989663SMark.Logan@Sun.COM		level = securelevel;
6999663SMark.Logan@Sun.COM		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
7009663SMark.Logan@Sun.COM		    newp == NULL)
7019663SMark.Logan@Sun.COM			return (error);
7029663SMark.Logan@Sun.COM		if (level < securelevel && p->p_pid != 1)
7039663SMark.Logan@Sun.COM			return (EPERM);
7049663SMark.Logan@Sun.COM		securelevel = level;
7059663SMark.Logan@Sun.COM		return (0);
7069663SMark.Logan@Sun.COM	case KERN_VNODE:
7079663SMark.Logan@Sun.COM		return (sysctl_vnode(oldp, oldlenp));
7089663SMark.Logan@Sun.COM	case KERN_PROC:
7099663SMark.Logan@Sun.COM		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
7109663SMark.Logan@Sun.COM	case KERN_FILE:
7119663SMark.Logan@Sun.COM		return (sysctl_file(oldp, oldlenp));
7129663SMark.Logan@Sun.COM#ifdef GPROF
7139663SMark.Logan@Sun.COM	case KERN_PROF:
7149663SMark.Logan@Sun.COM		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
7159663SMark.Logan@Sun.COM		    newp, newlen));
7169663SMark.Logan@Sun.COM#endif
7179663SMark.Logan@Sun.COM	case KERN_NTP_PLL:
7189663SMark.Logan@Sun.COM		return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp,
7199663SMark.Logan@Sun.COM				   newp, newlen, p));
7209663SMark.Logan@Sun.COM	case KERN_DUMPDEV:
7219663SMark.Logan@Sun.COM		ndumpdev = dumpdev;
7229663SMark.Logan@Sun.COM		error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev,
7239663SMark.Logan@Sun.COM				      sizeof ndumpdev);
7249663SMark.Logan@Sun.COM		if (!error && ndumpdev != dumpdev) {
7259663SMark.Logan@Sun.COM			error = setdumpdev(ndumpdev);
7269663SMark.Logan@Sun.COM		}
7279663SMark.Logan@Sun.COM		return error;
7289663SMark.Logan@Sun.COM	default:
7299663SMark.Logan@Sun.COM		return (EOPNOTSUPP);
7309663SMark.Logan@Sun.COM	}
7319663SMark.Logan@Sun.COM	/* NOTREACHED */
7329663SMark.Logan@Sun.COM}
7339663SMark.Logan@Sun.COM
7349663SMark.Logan@Sun.COM/*
7359663SMark.Logan@Sun.COM * hardware related system variables.
7369663SMark.Logan@Sun.COM */
7379663SMark.Logan@Sun.COMint
7389663SMark.Logan@Sun.COMhw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
7399663SMark.Logan@Sun.COM	int *name;
7409663SMark.Logan@Sun.COM	u_int namelen;
7419663SMark.Logan@Sun.COM	void *oldp;
7429663SMark.Logan@Sun.COM	size_t *oldlenp;
7439663SMark.Logan@Sun.COM	void *newp;
7449663SMark.Logan@Sun.COM	size_t newlen;
7459663SMark.Logan@Sun.COM	struct proc *p;
7469663SMark.Logan@Sun.COM{
7479663SMark.Logan@Sun.COM	/* almost all sysctl names at this level are terminal */
7489663SMark.Logan@Sun.COM	if (namelen != 1 && name[0] != HW_DEVCONF)
7499663SMark.Logan@Sun.COM		return (ENOTDIR);		/* overloaded */
7509663SMark.Logan@Sun.COM
7519663SMark.Logan@Sun.COM	switch (name[0]) {
7529663SMark.Logan@Sun.COM	case HW_PHYSMEM:
7539663SMark.Logan@Sun.COM		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
7549663SMark.Logan@Sun.COM	case HW_USERMEM:
7559663SMark.Logan@Sun.COM		return (sysctl_rdint(oldp, oldlenp, newp,
7569663SMark.Logan@Sun.COM		    ctob(physmem - cnt.v_wire_count)));
7579663SMark.Logan@Sun.COM	case HW_DEVCONF:
7589663SMark.Logan@Sun.COM		return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp,
7599663SMark.Logan@Sun.COM				   newp, newlen, p));
7609663SMark.Logan@Sun.COM	default:
7619663SMark.Logan@Sun.COM		return (EOPNOTSUPP);
7629663SMark.Logan@Sun.COM	}
7639663SMark.Logan@Sun.COM	/* NOTREACHED */
7649663SMark.Logan@Sun.COM}
7659663SMark.Logan@Sun.COM
7669663SMark.Logan@Sun.COM#ifdef DEBUG
7679663SMark.Logan@Sun.COM/*
7689663SMark.Logan@Sun.COM * Debugging related system variables.
7699663SMark.Logan@Sun.COM */
7709663SMark.Logan@Sun.COMstruct ctldebug debug0, debug1, debug2, debug3, debug4;
7719663SMark.Logan@Sun.COMstruct ctldebug debug5, debug6, debug7, debug8, debug9;
7729663SMark.Logan@Sun.COMstruct ctldebug debug10, debug11, debug12, debug13, debug14;
7739663SMark.Logan@Sun.COMstruct ctldebug debug15, debug16, debug17, debug18, debug19;
7749663SMark.Logan@Sun.COMstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
7759663SMark.Logan@Sun.COM	&debug0, &debug1, &debug2, &debug3, &debug4,
7769663SMark.Logan@Sun.COM	&debug5, &debug6, &debug7, &debug8, &debug9,
7779663SMark.Logan@Sun.COM	&debug10, &debug11, &debug12, &debug13, &debug14,
7789663SMark.Logan@Sun.COM	&debug15, &debug16, &debug17, &debug18, &debug19,
7799663SMark.Logan@Sun.COM};
7809663SMark.Logan@Sun.COMstatic int
7819663SMark.Logan@Sun.COMdebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
7829663SMark.Logan@Sun.COM	int *name;
7839663SMark.Logan@Sun.COM	u_int namelen;
7849663SMark.Logan@Sun.COM	void *oldp;
7859663SMark.Logan@Sun.COM	size_t *oldlenp;
7869663SMark.Logan@Sun.COM	void *newp;
7879663SMark.Logan@Sun.COM	size_t newlen;
7889663SMark.Logan@Sun.COM	struct proc *p;
7899663SMark.Logan@Sun.COM{
7909663SMark.Logan@Sun.COM	struct ctldebug *cdp;
7919663SMark.Logan@Sun.COM
7929663SMark.Logan@Sun.COM	/* all sysctl names at this level are name and field */
7939663SMark.Logan@Sun.COM	if (namelen != 2)
7949663SMark.Logan@Sun.COM		return (ENOTDIR);		/* overloaded */
7959663SMark.Logan@Sun.COM	cdp = debugvars[name[0]];
7969663SMark.Logan@Sun.COM	if (cdp->debugname == 0)
7979663SMark.Logan@Sun.COM		return (EOPNOTSUPP);
7989663SMark.Logan@Sun.COM	switch (name[1]) {
7999663SMark.Logan@Sun.COM	case CTL_DEBUG_NAME:
8009663SMark.Logan@Sun.COM		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
8019663SMark.Logan@Sun.COM	case CTL_DEBUG_VALUE:
8029663SMark.Logan@Sun.COM		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
8039663SMark.Logan@Sun.COM	default:
8049663SMark.Logan@Sun.COM		return (EOPNOTSUPP);
8059663SMark.Logan@Sun.COM	}
8069663SMark.Logan@Sun.COM	/* NOTREACHED */
8079663SMark.Logan@Sun.COM}
8089663SMark.Logan@Sun.COM#endif /* DEBUG */
8099663SMark.Logan@Sun.COM
8109663SMark.Logan@Sun.COM/*
8119663SMark.Logan@Sun.COM * Validate parameters and get old / set new parameters
8129663SMark.Logan@Sun.COM * for an integer-valued sysctl function.
8139663SMark.Logan@Sun.COM */
8149663SMark.Logan@Sun.COMint
8159663SMark.Logan@Sun.COMsysctl_int(oldp, oldlenp, newp, newlen, valp)
8169663SMark.Logan@Sun.COM	void *oldp;
8179663SMark.Logan@Sun.COM	size_t *oldlenp;
8189663SMark.Logan@Sun.COM	void *newp;
8199663SMark.Logan@Sun.COM	size_t newlen;
8209663SMark.Logan@Sun.COM	int *valp;
8219663SMark.Logan@Sun.COM{
8229663SMark.Logan@Sun.COM	int error = 0;
8239663SMark.Logan@Sun.COM
8249663SMark.Logan@Sun.COM	if (oldp && *oldlenp < sizeof(int))
8259663SMark.Logan@Sun.COM		return (ENOMEM);
8269663SMark.Logan@Sun.COM	if (newp && newlen != sizeof(int))
8279663SMark.Logan@Sun.COM		return (EINVAL);
8289663SMark.Logan@Sun.COM	*oldlenp = sizeof(int);
8299663SMark.Logan@Sun.COM	if (oldp)
8309663SMark.Logan@Sun.COM		error = copyout(valp, oldp, sizeof(int));
8319663SMark.Logan@Sun.COM	if (error == 0 && newp)
8329663SMark.Logan@Sun.COM		error = copyin(newp, valp, sizeof(int));
8339663SMark.Logan@Sun.COM	return (error);
8349663SMark.Logan@Sun.COM}
8359663SMark.Logan@Sun.COM
8369663SMark.Logan@Sun.COM/*
8379663SMark.Logan@Sun.COM * As above, but read-only.
8389663SMark.Logan@Sun.COM */
8399663SMark.Logan@Sun.COMint
8409663SMark.Logan@Sun.COMsysctl_rdint(oldp, oldlenp, newp, val)
8419663SMark.Logan@Sun.COM	void *oldp;
8429663SMark.Logan@Sun.COM	size_t *oldlenp;
8439663SMark.Logan@Sun.COM	void *newp;
8449663SMark.Logan@Sun.COM	int val;
8459663SMark.Logan@Sun.COM{
8469663SMark.Logan@Sun.COM	int error = 0;
8479663SMark.Logan@Sun.COM
8489663SMark.Logan@Sun.COM	if (oldp && *oldlenp < sizeof(int))
8499663SMark.Logan@Sun.COM		return (ENOMEM);
8509663SMark.Logan@Sun.COM	if (newp)
8519663SMark.Logan@Sun.COM		return (EPERM);
8529663SMark.Logan@Sun.COM	*oldlenp = sizeof(int);
8539663SMark.Logan@Sun.COM	if (oldp)
8549663SMark.Logan@Sun.COM		error = copyout((caddr_t)&val, oldp, sizeof(int));
8559663SMark.Logan@Sun.COM	return (error);
8569663SMark.Logan@Sun.COM}
8579663SMark.Logan@Sun.COM
8589663SMark.Logan@Sun.COM/*
8599663SMark.Logan@Sun.COM * Validate parameters and get old / set new parameters
8609663SMark.Logan@Sun.COM * for a string-valued sysctl function.
8619663SMark.Logan@Sun.COM */
8629663SMark.Logan@Sun.COMint
8639663SMark.Logan@Sun.COMsysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
8649663SMark.Logan@Sun.COM	void *oldp;
8659663SMark.Logan@Sun.COM	size_t *oldlenp;
8669663SMark.Logan@Sun.COM	void *newp;
8679663SMark.Logan@Sun.COM	size_t newlen;
8689663SMark.Logan@Sun.COM	char *str;
8699663SMark.Logan@Sun.COM	int maxlen;
8709663SMark.Logan@Sun.COM{
8719663SMark.Logan@Sun.COM	int len, error = 0, rval = 0;
8729663SMark.Logan@Sun.COM
8739663SMark.Logan@Sun.COM	len = strlen(str) + 1;
8749663SMark.Logan@Sun.COM	if (oldp && *oldlenp < len) {
8759663SMark.Logan@Sun.COM		len = *oldlenp;
8769663SMark.Logan@Sun.COM		rval = ENOMEM;
8779663SMark.Logan@Sun.COM	}
8789663SMark.Logan@Sun.COM	if (newp && newlen >= maxlen)
8799663SMark.Logan@Sun.COM		return (EINVAL);
8809663SMark.Logan@Sun.COM	if (oldp) {
8819663SMark.Logan@Sun.COM		*oldlenp = len;
8829663SMark.Logan@Sun.COM		error = copyout(str, oldp, len);
8839663SMark.Logan@Sun.COM		if (error)
8849663SMark.Logan@Sun.COM			rval = error;
8859663SMark.Logan@Sun.COM	}
8869663SMark.Logan@Sun.COM	if ((error == 0 || error == ENOMEM) && newp) {
8879663SMark.Logan@Sun.COM		error = copyin(newp, str, newlen);
8889663SMark.Logan@Sun.COM		if (error)
8899663SMark.Logan@Sun.COM			rval = error;
8909663SMark.Logan@Sun.COM		str[newlen] = 0;
8919663SMark.Logan@Sun.COM	}
8929663SMark.Logan@Sun.COM	return (rval);
8939663SMark.Logan@Sun.COM}
8949663SMark.Logan@Sun.COM
8959663SMark.Logan@Sun.COM/*
8969663SMark.Logan@Sun.COM * As above, but read-only.
8979663SMark.Logan@Sun.COM */
8989663SMark.Logan@Sun.COMint
8999663SMark.Logan@Sun.COMsysctl_rdstring(oldp, oldlenp, newp, str)
9009663SMark.Logan@Sun.COM	void *oldp;
9019663SMark.Logan@Sun.COM	size_t *oldlenp;
9029663SMark.Logan@Sun.COM	void *newp;
9039663SMark.Logan@Sun.COM	char *str;
9049663SMark.Logan@Sun.COM{
9059663SMark.Logan@Sun.COM	int len, error = 0, rval = 0;
9069663SMark.Logan@Sun.COM
9079663SMark.Logan@Sun.COM	len = strlen(str) + 1;
9089663SMark.Logan@Sun.COM	if (oldp && *oldlenp < len) {
9099663SMark.Logan@Sun.COM		len = *oldlenp;
9109663SMark.Logan@Sun.COM		rval = ENOMEM;
9119663SMark.Logan@Sun.COM	}
9129663SMark.Logan@Sun.COM	if (newp)
9139663SMark.Logan@Sun.COM		return (EPERM);
9149663SMark.Logan@Sun.COM	*oldlenp = len;
9159663SMark.Logan@Sun.COM	if (oldp)
9169663SMark.Logan@Sun.COM		error = copyout(str, oldp, len);
9179663SMark.Logan@Sun.COM		if (error)
9189663SMark.Logan@Sun.COM			rval = error;
9199663SMark.Logan@Sun.COM	return (rval);
9209663SMark.Logan@Sun.COM}
9219663SMark.Logan@Sun.COM
9229663SMark.Logan@Sun.COM/*
9239663SMark.Logan@Sun.COM * Validate parameters and get old / set new parameters
9249663SMark.Logan@Sun.COM * for a structure oriented sysctl function.
9259663SMark.Logan@Sun.COM */
9269663SMark.Logan@Sun.COMint
9279663SMark.Logan@Sun.COMsysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
9289663SMark.Logan@Sun.COM	void *oldp;
9299663SMark.Logan@Sun.COM	size_t *oldlenp;
9309663SMark.Logan@Sun.COM	void *newp;
9319663SMark.Logan@Sun.COM	size_t newlen;
9329663SMark.Logan@Sun.COM	void *sp;
9339663SMark.Logan@Sun.COM	int len;
9349663SMark.Logan@Sun.COM{
9359663SMark.Logan@Sun.COM	int error = 0;
9369663SMark.Logan@Sun.COM
9379663SMark.Logan@Sun.COM	if (oldp && *oldlenp < len)
9389663SMark.Logan@Sun.COM		return (ENOMEM);
9399663SMark.Logan@Sun.COM	if (newp && newlen > len)
9409663SMark.Logan@Sun.COM		return (EINVAL);
9419663SMark.Logan@Sun.COM	if (oldp) {
9429663SMark.Logan@Sun.COM		*oldlenp = len;
9439663SMark.Logan@Sun.COM		error = copyout(sp, oldp, len);
9449663SMark.Logan@Sun.COM	}
9459663SMark.Logan@Sun.COM	if (error == 0 && newp)
9469663SMark.Logan@Sun.COM		error = copyin(newp, sp, len);
9479663SMark.Logan@Sun.COM	return (error);
9489663SMark.Logan@Sun.COM}
9499663SMark.Logan@Sun.COM
9509663SMark.Logan@Sun.COM/*
9519663SMark.Logan@Sun.COM * Validate parameters and get old parameters
9529663SMark.Logan@Sun.COM * for a structure oriented sysctl function.
9539663SMark.Logan@Sun.COM */
9549663SMark.Logan@Sun.COMint
9559663SMark.Logan@Sun.COMsysctl_rdstruct(oldp, oldlenp, newp, sp, len)
9569663SMark.Logan@Sun.COM	void *oldp;
9579663SMark.Logan@Sun.COM	size_t *oldlenp;
9589663SMark.Logan@Sun.COM	void *newp, *sp;
9599663SMark.Logan@Sun.COM	int len;
9609663SMark.Logan@Sun.COM{
9619663SMark.Logan@Sun.COM	int error = 0;
9629663SMark.Logan@Sun.COM
9639663SMark.Logan@Sun.COM	if (oldp && *oldlenp < len)
9649663SMark.Logan@Sun.COM		return (ENOMEM);
9659663SMark.Logan@Sun.COM	if (newp)
9669663SMark.Logan@Sun.COM		return (EPERM);
9679663SMark.Logan@Sun.COM	*oldlenp = len;
9689663SMark.Logan@Sun.COM	if (oldp)
9699663SMark.Logan@Sun.COM		error = copyout(sp, oldp, len);
9709663SMark.Logan@Sun.COM	return (error);
9719663SMark.Logan@Sun.COM}
9729663SMark.Logan@Sun.COM
9739663SMark.Logan@Sun.COM/*
9749663SMark.Logan@Sun.COM * Get file structures.
9759663SMark.Logan@Sun.COM */
9769663SMark.Logan@Sun.COMint
9779663SMark.Logan@Sun.COMsysctl_file(where, sizep)
9789663SMark.Logan@Sun.COM	char *where;
9799663SMark.Logan@Sun.COM	size_t *sizep;
9809663SMark.Logan@Sun.COM{
9819663SMark.Logan@Sun.COM	int buflen, error;
9829663SMark.Logan@Sun.COM	struct file *fp;
9839663SMark.Logan@Sun.COM	char *start = where;
9849663SMark.Logan@Sun.COM
9859663SMark.Logan@Sun.COM	buflen = *sizep;
9869663SMark.Logan@Sun.COM	if (where == NULL) {
9879663SMark.Logan@Sun.COM		/*
9889663SMark.Logan@Sun.COM		 * overestimate by 10 files
9899663SMark.Logan@Sun.COM		 */
9909663SMark.Logan@Sun.COM		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
9919663SMark.Logan@Sun.COM		return (0);
9929663SMark.Logan@Sun.COM	}
9939663SMark.Logan@Sun.COM
9949663SMark.Logan@Sun.COM	/*
9959663SMark.Logan@Sun.COM	 * first copyout filehead
9969663SMark.Logan@Sun.COM	 */
9979663SMark.Logan@Sun.COM	if (buflen < sizeof(filehead)) {
9989663SMark.Logan@Sun.COM		*sizep = 0;
9999663SMark.Logan@Sun.COM		return (0);
10009663SMark.Logan@Sun.COM	}
10019663SMark.Logan@Sun.COM	error = copyout((caddr_t)&filehead, where, sizeof(filehead));
10029663SMark.Logan@Sun.COM	if (error)
10039663SMark.Logan@Sun.COM		return (error);
10049663SMark.Logan@Sun.COM	buflen -= sizeof(filehead);
10059663SMark.Logan@Sun.COM	where += sizeof(filehead);
10069663SMark.Logan@Sun.COM
10079663SMark.Logan@Sun.COM	/*
10089663SMark.Logan@Sun.COM	 * followed by an array of file structures
10099663SMark.Logan@Sun.COM	 */
10109663SMark.Logan@Sun.COM	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
10119663SMark.Logan@Sun.COM		if (buflen < sizeof(struct file)) {
10129663SMark.Logan@Sun.COM			*sizep = where - start;
10139663SMark.Logan@Sun.COM			return (ENOMEM);
10149663SMark.Logan@Sun.COM		}
10159663SMark.Logan@Sun.COM		error = copyout((caddr_t)fp, where, sizeof (struct file));
10169663SMark.Logan@Sun.COM		if (error)
10179663SMark.Logan@Sun.COM			return (error);
10189663SMark.Logan@Sun.COM		buflen -= sizeof(struct file);
10199663SMark.Logan@Sun.COM		where += sizeof(struct file);
10209663SMark.Logan@Sun.COM	}
10219663SMark.Logan@Sun.COM	*sizep = where - start;
10229663SMark.Logan@Sun.COM	return (0);
10239663SMark.Logan@Sun.COM}
10249663SMark.Logan@Sun.COM
10259663SMark.Logan@Sun.COM/*
10269663SMark.Logan@Sun.COM * try over estimating by 5 procs
10279663SMark.Logan@Sun.COM */
10289663SMark.Logan@Sun.COM#define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
10299663SMark.Logan@Sun.COM
10309663SMark.Logan@Sun.COMint
10319663SMark.Logan@Sun.COMsysctl_doproc(name, namelen, where, sizep)
10329663SMark.Logan@Sun.COM	int *name;
10339663SMark.Logan@Sun.COM	u_int namelen;
10349663SMark.Logan@Sun.COM	char *where;
10359663SMark.Logan@Sun.COM	size_t *sizep;
10369663SMark.Logan@Sun.COM{
10379663SMark.Logan@Sun.COM	register struct proc *p;
10389663SMark.Logan@Sun.COM	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
10399663SMark.Logan@Sun.COM	register int needed = 0;
10409663SMark.Logan@Sun.COM	int buflen = where != NULL ? *sizep : 0;
10419663SMark.Logan@Sun.COM	int doingzomb;
10429663SMark.Logan@Sun.COM	struct eproc eproc;
10439663SMark.Logan@Sun.COM	int error = 0;
10449663SMark.Logan@Sun.COM
10459663SMark.Logan@Sun.COM	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
10469663SMark.Logan@Sun.COM		return (EINVAL);
10479663SMark.Logan@Sun.COM	p = (struct proc *)allproc;
10489663SMark.Logan@Sun.COM	doingzomb = 0;
10499663SMark.Logan@Sun.COMagain:
10509663SMark.Logan@Sun.COM	for (; p != NULL; p = p->p_next) {
10519663SMark.Logan@Sun.COM		/*
10529663SMark.Logan@Sun.COM		 * Skip embryonic processes.
10539663SMark.Logan@Sun.COM		 */
10549663SMark.Logan@Sun.COM		if (p->p_stat == SIDL)
10559663SMark.Logan@Sun.COM			continue;
10569663SMark.Logan@Sun.COM		/*
10579663SMark.Logan@Sun.COM		 * TODO - make more efficient (see notes below).
10589663SMark.Logan@Sun.COM		 * do by session.
10599663SMark.Logan@Sun.COM		 */
10609663SMark.Logan@Sun.COM		switch (name[0]) {
10619663SMark.Logan@Sun.COM
10629663SMark.Logan@Sun.COM		case KERN_PROC_PID:
10639663SMark.Logan@Sun.COM			/* could do this with just a lookup */
10649663SMark.Logan@Sun.COM			if (p->p_pid != (pid_t)name[1])
10659663SMark.Logan@Sun.COM				continue;
10669663SMark.Logan@Sun.COM			break;
10679663SMark.Logan@Sun.COM
10689663SMark.Logan@Sun.COM		case KERN_PROC_PGRP:
10699663SMark.Logan@Sun.COM			/* could do this by traversing pgrp */
10709663SMark.Logan@Sun.COM			if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1])
10719663SMark.Logan@Sun.COM				continue;
10729663SMark.Logan@Sun.COM			break;
10739663SMark.Logan@Sun.COM
10749663SMark.Logan@Sun.COM		case KERN_PROC_TTY:
10759663SMark.Logan@Sun.COM			if ((p->p_flag & P_CONTROLT) == 0 ||
10769663SMark.Logan@Sun.COM			    p->p_session == NULL ||
10779663SMark.Logan@Sun.COM			    p->p_session->s_ttyp == NULL ||
10789663SMark.Logan@Sun.COM			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
10799663SMark.Logan@Sun.COM				continue;
10809663SMark.Logan@Sun.COM			break;
10819663SMark.Logan@Sun.COM
10829663SMark.Logan@Sun.COM		case KERN_PROC_UID:
10839663SMark.Logan@Sun.COM			if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1])
10849663SMark.Logan@Sun.COM				continue;
10859663SMark.Logan@Sun.COM			break;
10869663SMark.Logan@Sun.COM
10879663SMark.Logan@Sun.COM		case KERN_PROC_RUID:
10889663SMark.Logan@Sun.COM			if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1])
10899663SMark.Logan@Sun.COM				continue;
10909663SMark.Logan@Sun.COM			break;
10919663SMark.Logan@Sun.COM		}
10929663SMark.Logan@Sun.COM		if (buflen >= sizeof(struct kinfo_proc)) {
10939663SMark.Logan@Sun.COM			fill_eproc(p, &eproc);
10949663SMark.Logan@Sun.COM			error = copyout((caddr_t)p, &dp->kp_proc,
10959663SMark.Logan@Sun.COM			    sizeof(struct proc));
10969663SMark.Logan@Sun.COM			if (error)
10979663SMark.Logan@Sun.COM				return (error);
10989663SMark.Logan@Sun.COM			error = copyout((caddr_t)&eproc, &dp->kp_eproc,
10999663SMark.Logan@Sun.COM			    sizeof(eproc));
11009663SMark.Logan@Sun.COM			if (error)
11019663SMark.Logan@Sun.COM				return (error);
11029663SMark.Logan@Sun.COM			dp++;
11039663SMark.Logan@Sun.COM			buflen -= sizeof(struct kinfo_proc);
11049663SMark.Logan@Sun.COM		}
11059663SMark.Logan@Sun.COM		needed += sizeof(struct kinfo_proc);
11069663SMark.Logan@Sun.COM	}
11079663SMark.Logan@Sun.COM	if (doingzomb == 0) {
11089663SMark.Logan@Sun.COM		p = zombproc;
11099663SMark.Logan@Sun.COM		doingzomb++;
11109663SMark.Logan@Sun.COM		goto again;
11119663SMark.Logan@Sun.COM	}
11129663SMark.Logan@Sun.COM	if (where != NULL) {
11139663SMark.Logan@Sun.COM		*sizep = (caddr_t)dp - where;
11149663SMark.Logan@Sun.COM		if (needed > *sizep)
11159663SMark.Logan@Sun.COM			return (ENOMEM);
11169663SMark.Logan@Sun.COM	} else {
11179663SMark.Logan@Sun.COM		needed += KERN_PROCSLOP;
11189663SMark.Logan@Sun.COM		*sizep = needed;
11199663SMark.Logan@Sun.COM	}
11209663SMark.Logan@Sun.COM	return (0);
11219663SMark.Logan@Sun.COM}
11229663SMark.Logan@Sun.COM
11239663SMark.Logan@Sun.COM/*
11249663SMark.Logan@Sun.COM * Fill in an eproc structure for the specified process.
11259663SMark.Logan@Sun.COM */
11269663SMark.Logan@Sun.COMvoid
11279663SMark.Logan@Sun.COMfill_eproc(p, ep)
11289663SMark.Logan@Sun.COM	register struct proc *p;
11299663SMark.Logan@Sun.COM	register struct eproc *ep;
11309663SMark.Logan@Sun.COM{
11319663SMark.Logan@Sun.COM	register struct tty *tp;
11329663SMark.Logan@Sun.COM
11339663SMark.Logan@Sun.COM	bzero(ep, sizeof(*ep));
11349663SMark.Logan@Sun.COM
11359663SMark.Logan@Sun.COM	ep->e_paddr = p;
11369663SMark.Logan@Sun.COM	if (p->p_cred) {
11379663SMark.Logan@Sun.COM		ep->e_pcred = *p->p_cred;
11389663SMark.Logan@Sun.COM		if (p->p_ucred)
11399663SMark.Logan@Sun.COM			ep->e_ucred = *p->p_ucred;
11409663SMark.Logan@Sun.COM	}
11419663SMark.Logan@Sun.COM	if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) {
11429663SMark.Logan@Sun.COM		register struct vmspace *vm = p->p_vmspace;
11439663SMark.Logan@Sun.COM
11449663SMark.Logan@Sun.COM#ifdef pmap_resident_count
11459663SMark.Logan@Sun.COM		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
11469663SMark.Logan@Sun.COM#else
11479663SMark.Logan@Sun.COM		ep->e_vm.vm_rssize = vm->vm_rssize;
11489663SMark.Logan@Sun.COM#endif
11499663SMark.Logan@Sun.COM		ep->e_vm.vm_tsize = vm->vm_tsize;
11509663SMark.Logan@Sun.COM		ep->e_vm.vm_dsize = vm->vm_dsize;
11519663SMark.Logan@Sun.COM		ep->e_vm.vm_ssize = vm->vm_ssize;
11529663SMark.Logan@Sun.COM#ifndef sparc
11539663SMark.Logan@Sun.COM		ep->e_vm.vm_pmap = vm->vm_pmap;
11549663SMark.Logan@Sun.COM#endif
11559663SMark.Logan@Sun.COM	}
11569663SMark.Logan@Sun.COM	if (p->p_pptr)
11579663SMark.Logan@Sun.COM		ep->e_ppid = p->p_pptr->p_pid;
11589663SMark.Logan@Sun.COM	if (p->p_pgrp) {
11599663SMark.Logan@Sun.COM		ep->e_sess = p->p_pgrp->pg_session;
11609663SMark.Logan@Sun.COM		ep->e_pgid = p->p_pgrp->pg_id;
11619663SMark.Logan@Sun.COM		ep->e_jobc = p->p_pgrp->pg_jobc;
11629663SMark.Logan@Sun.COM	}
11639663SMark.Logan@Sun.COM	if ((p->p_flag & P_CONTROLT) &&
11649663SMark.Logan@Sun.COM	    (ep->e_sess != NULL) &&
11659663SMark.Logan@Sun.COM	    ((tp = ep->e_sess->s_ttyp) != NULL)) {
11669663SMark.Logan@Sun.COM		ep->e_tdev = tp->t_dev;
11679663SMark.Logan@Sun.COM		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
11689663SMark.Logan@Sun.COM		ep->e_tsess = tp->t_session;
11699663SMark.Logan@Sun.COM	} else
11709663SMark.Logan@Sun.COM		ep->e_tdev = NODEV;
11719663SMark.Logan@Sun.COM	if (ep->e_sess && ep->e_sess->s_ttyvp)
11729663SMark.Logan@Sun.COM		ep->e_flag = EPROC_CTTY;
11739663SMark.Logan@Sun.COM	if (SESS_LEADER(p))
11749663SMark.Logan@Sun.COM		ep->e_flag |= EPROC_SLEADER;
11759663SMark.Logan@Sun.COM	if (p->p_wmesg) {
11769663SMark.Logan@Sun.COM		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
11779663SMark.Logan@Sun.COM		ep->e_wmesg[WMESGLEN] = 0;
11789663SMark.Logan@Sun.COM	}
11799663SMark.Logan@Sun.COM}
11809663SMark.Logan@Sun.COM
11819663SMark.Logan@Sun.COM#ifdef COMPAT_43
11829663SMark.Logan@Sun.COM#include <sys/socket.h>
11839663SMark.Logan@Sun.COM#define	KINFO_PROC		(0<<8)
11849663SMark.Logan@Sun.COM#define	KINFO_RT		(1<<8)
11859663SMark.Logan@Sun.COM#define	KINFO_VNODE		(2<<8)
11869663SMark.Logan@Sun.COM#define	KINFO_FILE		(3<<8)
11879663SMark.Logan@Sun.COM#define	KINFO_METER		(4<<8)
11889663SMark.Logan@Sun.COM#define	KINFO_LOADAVG		(5<<8)
11899663SMark.Logan@Sun.COM#define	KINFO_CLOCKRATE		(6<<8)
11909663SMark.Logan@Sun.COM
11919663SMark.Logan@Sun.COM/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
11929663SMark.Logan@Sun.COM#define	KINFO_BSDI_SYSINFO	(101<<8)
11939663SMark.Logan@Sun.COM
11949663SMark.Logan@Sun.COM/*
11959663SMark.Logan@Sun.COM * XXX this is bloat, but I hope it's better here than on the potentially
11969663SMark.Logan@Sun.COM * limited kernel stack...  -Peter
11979663SMark.Logan@Sun.COM */
11989663SMark.Logan@Sun.COM
11999663SMark.Logan@Sun.COMstruct {
12009663SMark.Logan@Sun.COM	int	bsdi_machine;		/* "i386" on BSD/386 */
12019663SMark.Logan@Sun.COM/*      ^^^ this is an offset to the string, relative to the struct start */
12029663SMark.Logan@Sun.COM	char	*pad0;
12039663SMark.Logan@Sun.COM	long	pad1;
12049663SMark.Logan@Sun.COM	long	pad2;
12059663SMark.Logan@Sun.COM	long	pad3;
12069663SMark.Logan@Sun.COM	u_long	pad4;
12079663SMark.Logan@Sun.COM	u_long	pad5;
12089663SMark.Logan@Sun.COM	u_long	pad6;
12099663SMark.Logan@Sun.COM
12109663SMark.Logan@Sun.COM	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
12119663SMark.Logan@Sun.COM	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
12129663SMark.Logan@Sun.COM	long	pad7;
12139663SMark.Logan@Sun.COM	long	pad8;
12149663SMark.Logan@Sun.COM	char	*pad9;
12159663SMark.Logan@Sun.COM
12169663SMark.Logan@Sun.COM	long	pad10;
12179663SMark.Logan@Sun.COM	long	pad11;
12189663SMark.Logan@Sun.COM	int	pad12;
12199663SMark.Logan@Sun.COM	long	pad13;
12209663SMark.Logan@Sun.COM	quad_t	pad14;
12219663SMark.Logan@Sun.COM	long	pad15;
12229663SMark.Logan@Sun.COM
12239663SMark.Logan@Sun.COM	struct	timeval pad16;
12249663SMark.Logan@Sun.COM	/* we dont set this, because BSDI's uname used gethostname() instead */
12259663SMark.Logan@Sun.COM	int	bsdi_hostname;		/* hostname on BSD/386 */
12269663SMark.Logan@Sun.COM
12279663SMark.Logan@Sun.COM	/* the actual string data is appended here */
12289663SMark.Logan@Sun.COM
12299663SMark.Logan@Sun.COM} bsdi_si;
12309663SMark.Logan@Sun.COM/*
12319663SMark.Logan@Sun.COM * this data is appended to the end of the bsdi_si structure during copyout.
12329663SMark.Logan@Sun.COM * The "char *" offsets are relative to the base of the bsdi_si struct.
12339663SMark.Logan@Sun.COM * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
12349663SMark.Logan@Sun.COM * should not exceed the length of the buffer here... (or else!! :-)
12359663SMark.Logan@Sun.COM */
12369663SMark.Logan@Sun.COMchar bsdi_strings[80];	/* It had better be less than this! */
12379663SMark.Logan@Sun.COM
12389663SMark.Logan@Sun.COM#ifndef _SYS_SYSPROTO_H_
12399663SMark.Logan@Sun.COMstruct getkerninfo_args {
12409663SMark.Logan@Sun.COM	int	op;
12419663SMark.Logan@Sun.COM	char	*where;
12429663SMark.Logan@Sun.COM	int	*size;
12439663SMark.Logan@Sun.COM	int	arg;
12449663SMark.Logan@Sun.COM};
12459663SMark.Logan@Sun.COM#endif
12469663SMark.Logan@Sun.COM
12479663SMark.Logan@Sun.COMint
12489663SMark.Logan@Sun.COMogetkerninfo(p, uap, retval)
12499663SMark.Logan@Sun.COM	struct proc *p;
12509663SMark.Logan@Sun.COM	register struct getkerninfo_args *uap;
12519663SMark.Logan@Sun.COM	int *retval;
12529663SMark.Logan@Sun.COM{
12539663SMark.Logan@Sun.COM	int error, name[6];
12549663SMark.Logan@Sun.COM	u_int size;
12559663SMark.Logan@Sun.COM
12569663SMark.Logan@Sun.COM	switch (uap->op & 0xff00) {
12579663SMark.Logan@Sun.COM
12589663SMark.Logan@Sun.COM	case KINFO_RT:
12599663SMark.Logan@Sun.COM		name[0] = CTL_NET;
12609663SMark.Logan@Sun.COM		name[1] = PF_ROUTE;
12619663SMark.Logan@Sun.COM		name[2] = 0;
12629663SMark.Logan@Sun.COM		name[3] = (uap->op & 0xff0000) >> 16;
12639663SMark.Logan@Sun.COM		name[4] = uap->op & 0xff;
12649663SMark.Logan@Sun.COM		name[5] = uap->arg;
12659663SMark.Logan@Sun.COM		error = userland_sysctl(p, name, 6, uap->where, uap->size,
12669663SMark.Logan@Sun.COM			0, 0, 0, 0);
12679663SMark.Logan@Sun.COM		break;
12689663SMark.Logan@Sun.COM
12699663SMark.Logan@Sun.COM	case KINFO_VNODE:
12709663SMark.Logan@Sun.COM		name[0] = CTL_KERN;
12719663SMark.Logan@Sun.COM		name[1] = KERN_VNODE;
12729663SMark.Logan@Sun.COM		error = userland_sysctl(p, name, 2, uap->where, uap->size,
12739663SMark.Logan@Sun.COM			0, 0, 0, 0);
12749663SMark.Logan@Sun.COM		break;
12759663SMark.Logan@Sun.COM
12769663SMark.Logan@Sun.COM	case KINFO_PROC:
12779663SMark.Logan@Sun.COM		name[0] = CTL_KERN;
12789663SMark.Logan@Sun.COM		name[1] = KERN_PROC;
12799663SMark.Logan@Sun.COM		name[2] = uap->op & 0xff;
12809663SMark.Logan@Sun.COM		name[3] = uap->arg;
12819663SMark.Logan@Sun.COM		error = userland_sysctl(p, name, 4, uap->where, uap->size,
12829663SMark.Logan@Sun.COM			0, 0, 0, 0);
12839663SMark.Logan@Sun.COM		break;
12849663SMark.Logan@Sun.COM
12859663SMark.Logan@Sun.COM	case KINFO_FILE:
12869663SMark.Logan@Sun.COM		name[0] = CTL_KERN;
12879663SMark.Logan@Sun.COM		name[1] = KERN_FILE;
12889663SMark.Logan@Sun.COM		error = userland_sysctl(p, name, 2, uap->where, uap->size,
12899663SMark.Logan@Sun.COM			0, 0, 0, 0);
12909663SMark.Logan@Sun.COM		break;
12919663SMark.Logan@Sun.COM
12929663SMark.Logan@Sun.COM	case KINFO_METER:
12939663SMark.Logan@Sun.COM		name[0] = CTL_VM;
12949663SMark.Logan@Sun.COM		name[1] = VM_METER;
12959663SMark.Logan@Sun.COM		error = userland_sysctl(p, name, 2, uap->where, uap->size,
12969663SMark.Logan@Sun.COM			0, 0, 0, 0);
12979663SMark.Logan@Sun.COM		break;
12989663SMark.Logan@Sun.COM
12999663SMark.Logan@Sun.COM	case KINFO_LOADAVG:
13009663SMark.Logan@Sun.COM		name[0] = CTL_VM;
13019663SMark.Logan@Sun.COM		name[1] = VM_LOADAVG;
13029663SMark.Logan@Sun.COM		error = userland_sysctl(p, name, 2, uap->where, uap->size,
13039663SMark.Logan@Sun.COM			0, 0, 0, 0);
13049663SMark.Logan@Sun.COM		break;
13059663SMark.Logan@Sun.COM
13069663SMark.Logan@Sun.COM	case KINFO_CLOCKRATE:
13079663SMark.Logan@Sun.COM		name[0] = CTL_KERN;
13089663SMark.Logan@Sun.COM		name[1] = KERN_CLOCKRATE;
13099663SMark.Logan@Sun.COM		error = userland_sysctl(p, name, 2, uap->where, uap->size,
13109663SMark.Logan@Sun.COM			0, 0, 0, 0);
13119663SMark.Logan@Sun.COM		break;
13129663SMark.Logan@Sun.COM
13139663SMark.Logan@Sun.COM	case KINFO_BSDI_SYSINFO: {
13149663SMark.Logan@Sun.COM		/*
13159663SMark.Logan@Sun.COM		 * this is pretty crude, but it's just enough for uname()
13169663SMark.Logan@Sun.COM		 * from BSDI's 1.x libc to work.
13179663SMark.Logan@Sun.COM		 *
13189663SMark.Logan@Sun.COM		 * In particular, it doesn't return the same results when
13199663SMark.Logan@Sun.COM		 * the supplied buffer is too small.  BSDI's version apparently
13209663SMark.Logan@Sun.COM		 * will return the amount copied, and set the *size to how
13219663SMark.Logan@Sun.COM		 * much was needed.  The emulation framework here isn't capable
13229663SMark.Logan@Sun.COM		 * of that, so we just set both to the amount copied.
13239663SMark.Logan@Sun.COM		 * BSDI's 2.x product apparently fails with ENOMEM in this
13249663SMark.Logan@Sun.COM		 * scenario.
13259663SMark.Logan@Sun.COM		 */
13269663SMark.Logan@Sun.COM
13279663SMark.Logan@Sun.COM		u_int needed;
13289663SMark.Logan@Sun.COM		u_int left;
13299663SMark.Logan@Sun.COM		char *s;
13309663SMark.Logan@Sun.COM
13319663SMark.Logan@Sun.COM		bzero((char *)&bsdi_si, sizeof(bsdi_si));
13329663SMark.Logan@Sun.COM		bzero(bsdi_strings, sizeof(bsdi_strings));
13339663SMark.Logan@Sun.COM
13349663SMark.Logan@Sun.COM		s = bsdi_strings;
13359663SMark.Logan@Sun.COM
13369663SMark.Logan@Sun.COM		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
13379663SMark.Logan@Sun.COM		strcpy(s, ostype);
13389663SMark.Logan@Sun.COM		s += strlen(s) + 1;
13399663SMark.Logan@Sun.COM
13409663SMark.Logan@Sun.COM		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
13419663SMark.Logan@Sun.COM		strcpy(s, osrelease);
13429663SMark.Logan@Sun.COM		s += strlen(s) + 1;
13439663SMark.Logan@Sun.COM
13449663SMark.Logan@Sun.COM		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
13459663SMark.Logan@Sun.COM		strcpy(s, machine);
13469663SMark.Logan@Sun.COM		s += strlen(s) + 1;
13479663SMark.Logan@Sun.COM
13489663SMark.Logan@Sun.COM		needed = sizeof(bsdi_si) + (s - bsdi_strings);
13499663SMark.Logan@Sun.COM
13509663SMark.Logan@Sun.COM		if (uap->where == NULL) {
13519663SMark.Logan@Sun.COM			/* process is asking how much buffer to supply.. */
13529663SMark.Logan@Sun.COM			size = needed;
13539663SMark.Logan@Sun.COM			error = 0;
13549663SMark.Logan@Sun.COM			break;
13559663SMark.Logan@Sun.COM		}
13569663SMark.Logan@Sun.COM
13579663SMark.Logan@Sun.COM
13589663SMark.Logan@Sun.COM		/* if too much buffer supplied, trim it down */
13599663SMark.Logan@Sun.COM		if (size > needed)
13609663SMark.Logan@Sun.COM			size = needed;
13619663SMark.Logan@Sun.COM
13629663SMark.Logan@Sun.COM		/* how much of the buffer is remaining */
13639663SMark.Logan@Sun.COM		left = size;
13649663SMark.Logan@Sun.COM
13659663SMark.Logan@Sun.COM		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
13669663SMark.Logan@Sun.COM			break;
13679663SMark.Logan@Sun.COM
13689663SMark.Logan@Sun.COM		/* is there any point in continuing? */
13699663SMark.Logan@Sun.COM		if (left > sizeof(bsdi_si)) {
13709663SMark.Logan@Sun.COM			left -= sizeof(bsdi_si);
13719663SMark.Logan@Sun.COM			error = copyout(&bsdi_strings,
13729663SMark.Logan@Sun.COM					uap->where + sizeof(bsdi_si), left);
13739663SMark.Logan@Sun.COM		}
13749663SMark.Logan@Sun.COM		break;
13759663SMark.Logan@Sun.COM	}
13769663SMark.Logan@Sun.COM
13779663SMark.Logan@Sun.COM	default:
13789663SMark.Logan@Sun.COM		return (EOPNOTSUPP);
13799663SMark.Logan@Sun.COM	}
13809663SMark.Logan@Sun.COM	if (error)
13819663SMark.Logan@Sun.COM		return (error);
13829663SMark.Logan@Sun.COM	*retval = size;
13839663SMark.Logan@Sun.COM	if (uap->size)
13849663SMark.Logan@Sun.COM		error = copyout((caddr_t)&size, (caddr_t)uap->size,
13859663SMark.Logan@Sun.COM		    sizeof(size));
13869663SMark.Logan@Sun.COM	return (error);
13879663SMark.Logan@Sun.COM}
13889663SMark.Logan@Sun.COM#endif /* COMPAT_43 */
13899663SMark.Logan@Sun.COM