kern_sysctl.c revision 3308
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 *
81541Srgrimes * Redistribution and use in source and binary forms, with or without
91541Srgrimes * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes * 3. All advertising materials mentioning features or use of this software
171541Srgrimes *    must display the following acknowledgement:
181541Srgrimes *	This product includes software developed by the University of
191541Srgrimes *	California, Berkeley and its contributors.
201541Srgrimes * 4. Neither the name of the University nor the names of its contributors
211541Srgrimes *    may be used to endorse or promote products derived from this software
221541Srgrimes *    without specific prior written permission.
231541Srgrimes *
241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341541Srgrimes * SUCH DAMAGE.
351541Srgrimes *
361541Srgrimes *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
373308Sphk * $Id: kern_sysctl.c,v 1.15 1994/09/23 19:07:17 wollman Exp $
381541Srgrimes */
391541Srgrimes
401541Srgrimes/*
411541Srgrimes * sysctl system call.
421541Srgrimes */
431541Srgrimes
441541Srgrimes#include <sys/param.h>
451541Srgrimes#include <sys/systm.h>
461541Srgrimes#include <sys/kernel.h>
471541Srgrimes#include <sys/malloc.h>
481541Srgrimes#include <sys/proc.h>
491541Srgrimes#include <sys/file.h>
501541Srgrimes#include <sys/vnode.h>
511541Srgrimes#include <sys/unistd.h>
521541Srgrimes#include <sys/buf.h>
531541Srgrimes#include <sys/ioctl.h>
541541Srgrimes#include <sys/tty.h>
551541Srgrimes#include <vm/vm.h>
561541Srgrimes#include <sys/sysctl.h>
571541Srgrimes
581541Srgrimessysctlfn kern_sysctl;
591541Srgrimessysctlfn hw_sysctl;
601541Srgrimes#ifdef DEBUG
611541Srgrimessysctlfn debug_sysctl;
621541Srgrimes#endif
631541Srgrimesextern sysctlfn vm_sysctl;
641541Srgrimesextern sysctlfn fs_sysctl;
651541Srgrimesextern sysctlfn net_sysctl;
661541Srgrimesextern sysctlfn cpu_sysctl;
672858Swollmanextern sysctlfn ntp_sysctl;
681541Srgrimes
691541Srgrimes/*
701541Srgrimes * Locking and stats
711541Srgrimes */
721541Srgrimesstatic struct sysctl_lock {
731541Srgrimes	int	sl_lock;
741541Srgrimes	int	sl_want;
751541Srgrimes	int	sl_locked;
761541Srgrimes} memlock;
771541Srgrimes
781541Srgrimesstruct sysctl_args {
791541Srgrimes	int	*name;
801541Srgrimes	u_int	namelen;
811541Srgrimes	void	*old;
821541Srgrimes	size_t	*oldlenp;
831541Srgrimes	void	*new;
841541Srgrimes	size_t	newlen;
851541Srgrimes};
861541Srgrimes
871541Srgrimesint
881541Srgrimes__sysctl(p, uap, retval)
891541Srgrimes	struct proc *p;
901541Srgrimes	register struct sysctl_args *uap;
911541Srgrimes	int *retval;
921541Srgrimes{
931541Srgrimes	int error, dolock = 1;
941549Srgrimes	u_int savelen = 0, oldlen = 0;
951541Srgrimes	sysctlfn *fn;
961541Srgrimes	int name[CTL_MAXNAME];
971541Srgrimes
981541Srgrimes	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
991541Srgrimes		return (error);
1001541Srgrimes	/*
1011541Srgrimes	 * all top-level sysctl names are non-terminal
1021541Srgrimes	 */
1031541Srgrimes	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1041541Srgrimes		return (EINVAL);
1053308Sphk 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1063308Sphk 	if (error)
1071541Srgrimes		return (error);
1081541Srgrimes
1091541Srgrimes	switch (name[0]) {
1101541Srgrimes	case CTL_KERN:
1111541Srgrimes		fn = kern_sysctl;
1122903Sache		if (name[1] != KERN_VNODE)      /* XXX */
1131541Srgrimes			dolock = 0;
1141541Srgrimes		break;
1151541Srgrimes	case CTL_HW:
1161541Srgrimes		fn = hw_sysctl;
1171541Srgrimes		break;
1181541Srgrimes	case CTL_VM:
1191541Srgrimes		fn = vm_sysctl;
1201541Srgrimes		break;
1211541Srgrimes	case CTL_NET:
1221541Srgrimes		fn = net_sysctl;
1231541Srgrimes		break;
1241541Srgrimes	case CTL_FS:
1251541Srgrimes		fn = fs_sysctl;
1261541Srgrimes		break;
1271541Srgrimes	case CTL_MACHDEP:
1281541Srgrimes		fn = cpu_sysctl;
1291541Srgrimes		break;
1301541Srgrimes#ifdef DEBUG
1311541Srgrimes	case CTL_DEBUG:
1321541Srgrimes		fn = debug_sysctl;
1331541Srgrimes		break;
1341541Srgrimes#endif
1351541Srgrimes	default:
1361541Srgrimes		return (EOPNOTSUPP);
1371541Srgrimes	}
1381541Srgrimes
1391541Srgrimes	if (uap->oldlenp &&
1401541Srgrimes	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
1411541Srgrimes		return (error);
1421541Srgrimes	if (uap->old != NULL) {
1431541Srgrimes		if (!useracc(uap->old, oldlen, B_WRITE))
1441541Srgrimes			return (EFAULT);
1451541Srgrimes		while (memlock.sl_lock) {
1461541Srgrimes			memlock.sl_want = 1;
1471541Srgrimes			sleep((caddr_t)&memlock, PRIBIO+1);
1481541Srgrimes			memlock.sl_locked++;
1491541Srgrimes		}
1501541Srgrimes		memlock.sl_lock = 1;
1511541Srgrimes		if (dolock)
1521541Srgrimes			vslock(uap->old, oldlen);
1531541Srgrimes		savelen = oldlen;
1541541Srgrimes	}
1551541Srgrimes	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
1561541Srgrimes	    uap->new, uap->newlen, p);
1571541Srgrimes	if (uap->old != NULL) {
1581541Srgrimes		if (dolock)
1591541Srgrimes			vsunlock(uap->old, savelen, B_WRITE);
1601541Srgrimes		memlock.sl_lock = 0;
1611541Srgrimes		if (memlock.sl_want) {
1621541Srgrimes			memlock.sl_want = 0;
1631541Srgrimes			wakeup((caddr_t)&memlock);
1641541Srgrimes		}
1651541Srgrimes	}
1661541Srgrimes	if (error)
1671541Srgrimes		return (error);
1681541Srgrimes	if (uap->oldlenp)
1691541Srgrimes		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
1701541Srgrimes	*retval = oldlen;
1711541Srgrimes	return (0);
1721541Srgrimes}
1731541Srgrimes
1741541Srgrimes/*
1751541Srgrimes * Attributes stored in the kernel.
1761541Srgrimes */
1771541Srgrimeschar hostname[MAXHOSTNAMELEN];
1781541Srgrimesint hostnamelen;
1791925Swollmanchar domainname[MAXHOSTNAMELEN];
1801925Swollmanint domainnamelen;
1811541Srgrimeslong hostid;
1821995Swollmanint securelevel = -1;
1833038Swollmanchar kernelname[MAXPATHLEN] = "/kernel";
1841952Swollmanextern int vfs_update_wakeup;
1851952Swollmanextern int vfs_update_interval;
1862004Swollmanextern int osreldate;
1871541Srgrimes
1881541Srgrimes/*
1891541Srgrimes * kernel related system variables.
1901541Srgrimes */
1911549Srgrimesint
1921541Srgrimeskern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1931541Srgrimes	int *name;
1941541Srgrimes	u_int namelen;
1951541Srgrimes	void *oldp;
1961541Srgrimes	size_t *oldlenp;
1971541Srgrimes	void *newp;
1981541Srgrimes	size_t newlen;
1991541Srgrimes	struct proc *p;
2001541Srgrimes{
2011541Srgrimes	int error, level, inthostid;
2022112Swollman	extern char ostype[], osrelease[];
2031541Srgrimes
2041541Srgrimes	/* all sysctl names at this level are terminal */
2052858Swollman	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
2062858Swollman			      || name[0] == KERN_NTP_PLL))
2071541Srgrimes		return (ENOTDIR);		/* overloaded */
2081541Srgrimes
2091541Srgrimes	switch (name[0]) {
2101541Srgrimes	case KERN_OSTYPE:
2111541Srgrimes		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
2121541Srgrimes	case KERN_OSRELEASE:
2131541Srgrimes		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
2141541Srgrimes	case KERN_OSREV:
2151541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
2161541Srgrimes	case KERN_VERSION:
2171541Srgrimes		return (sysctl_rdstring(oldp, oldlenp, newp, version));
2182004Swollman	case KERN_OSRELDATE:
2192004Swollman		return (sysctl_rdint(oldp, oldlenp, newp, osreldate));
2203038Swollman	case KERN_BOOTFILE:
2213038Swollman		return (sysctl_string(oldp, oldlenp, newp, newlen,
2223038Swollman				      kernelname, sizeof kernelname));
2231541Srgrimes	case KERN_MAXVNODES:
2241541Srgrimes		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
2251541Srgrimes	case KERN_MAXPROC:
2261541Srgrimes		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
2271541Srgrimes	case KERN_MAXFILES:
2281541Srgrimes		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
2291952Swollman	case KERN_UPDATEINTERVAL:
2301952Swollman		/*
2311952Swollman		 * NB: this simple-minded approach only works because
2321952Swollman		 * `tsleep' takes a timeout argument of 0 as meaning
2331952Swollman		 * `no timeout'.
2341952Swollman		 */
2351952Swollman		error = sysctl_int(oldp, oldlenp, newp, newlen,
2361952Swollman				   &vfs_update_interval);
2371952Swollman		if(!error) {
2381952Swollman			wakeup(&vfs_update_wakeup);
2391952Swollman		}
2401952Swollman		return error;
2411541Srgrimes	case KERN_ARGMAX:
2421541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
2431541Srgrimes	case KERN_SECURELVL:
2441541Srgrimes		level = securelevel;
2451541Srgrimes		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
2461541Srgrimes		    newp == NULL)
2471541Srgrimes			return (error);
2481541Srgrimes		if (level < securelevel && p->p_pid != 1)
2491541Srgrimes			return (EPERM);
2501541Srgrimes		securelevel = level;
2511541Srgrimes		return (0);
2521541Srgrimes	case KERN_HOSTNAME:
2531541Srgrimes		error = sysctl_string(oldp, oldlenp, newp, newlen,
2541541Srgrimes		    hostname, sizeof(hostname));
2551541Srgrimes		if (newp && !error)
2561541Srgrimes			hostnamelen = newlen;
2571541Srgrimes		return (error);
2581925Swollman	case KERN_DOMAINNAME:
2591925Swollman		error = sysctl_string(oldp, oldlenp, newp, newlen,
2601925Swollman		    domainname, sizeof(domainname));
2611925Swollman		if (newp && !error)
2621925Swollman			domainnamelen = newlen;
2631925Swollman		return (error);
2641541Srgrimes	case KERN_HOSTID:
2651541Srgrimes		inthostid = hostid;  /* XXX assumes sizeof long <= sizeof int */
2661541Srgrimes		error =  sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
2671541Srgrimes		hostid = inthostid;
2681541Srgrimes		return (error);
2691541Srgrimes	case KERN_CLOCKRATE:
2701541Srgrimes		return (sysctl_clockrate(oldp, oldlenp));
2711541Srgrimes	case KERN_BOOTTIME:
2721541Srgrimes		return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
2731541Srgrimes		    sizeof(struct timeval)));
2741541Srgrimes	case KERN_VNODE:
2751541Srgrimes		return (sysctl_vnode(oldp, oldlenp));
2761541Srgrimes	case KERN_PROC:
2771541Srgrimes		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
2781541Srgrimes	case KERN_FILE:
2791541Srgrimes		return (sysctl_file(oldp, oldlenp));
2801541Srgrimes#ifdef GPROF
2811541Srgrimes	case KERN_PROF:
2821541Srgrimes		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
2831541Srgrimes		    newp, newlen));
2841541Srgrimes#endif
2851541Srgrimes	case KERN_POSIX1:
2861541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
2871541Srgrimes	case KERN_NGROUPS:
2881541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
2891541Srgrimes	case KERN_JOB_CONTROL:
2901541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, 1));
2911541Srgrimes	case KERN_SAVED_IDS:
2921541Srgrimes#ifdef _POSIX_SAVED_IDS
2931541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, 1));
2941541Srgrimes#else
2951541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, 0));
2961541Srgrimes#endif
2972858Swollman	case KERN_NTP_PLL:
2982858Swollman		return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp,
2992858Swollman				   newp, newlen, p));
3001541Srgrimes	default:
3011541Srgrimes		return (EOPNOTSUPP);
3021541Srgrimes	}
3031541Srgrimes	/* NOTREACHED */
3041541Srgrimes}
3051541Srgrimes
3061541Srgrimes/*
3071541Srgrimes * hardware related system variables.
3081541Srgrimes */
3091549Srgrimesint
3101541Srgrimeshw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
3111541Srgrimes	int *name;
3121541Srgrimes	u_int namelen;
3131541Srgrimes	void *oldp;
3141541Srgrimes	size_t *oldlenp;
3151541Srgrimes	void *newp;
3161541Srgrimes	size_t newlen;
3171541Srgrimes	struct proc *p;
3181541Srgrimes{
3191541Srgrimes	extern char machine[], cpu_model[];
3202631Swollman	extern int hw_float;
3211541Srgrimes
3221541Srgrimes	/* all sysctl names at this level are terminal */
3231541Srgrimes	if (namelen != 1)
3241541Srgrimes		return (ENOTDIR);		/* overloaded */
3251541Srgrimes
3261541Srgrimes	switch (name[0]) {
3271541Srgrimes	case HW_MACHINE:
3281541Srgrimes		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
3291541Srgrimes	case HW_MODEL:
3301541Srgrimes		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
3311541Srgrimes	case HW_NCPU:
3321541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
3331541Srgrimes	case HW_BYTEORDER:
3341541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
3351541Srgrimes	case HW_PHYSMEM:
3361541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
3371541Srgrimes	case HW_USERMEM:
3381541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp,
3391541Srgrimes		    ctob(physmem - cnt.v_wire_count)));
3401541Srgrimes	case HW_PAGESIZE:
3411541Srgrimes		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
3422631Swollman	case HW_FLOATINGPT:
3432631Swollman		return (sysctl_rdint(oldp, oldlenp, newp, hw_float));
3441541Srgrimes	default:
3451541Srgrimes		return (EOPNOTSUPP);
3461541Srgrimes	}
3471541Srgrimes	/* NOTREACHED */
3481541Srgrimes}
3491541Srgrimes
3501541Srgrimes#ifdef DEBUG
3511541Srgrimes/*
3521541Srgrimes * Debugging related system variables.
3531541Srgrimes */
3541541Srgrimesstruct ctldebug debug0, debug1, debug2, debug3, debug4;
3551541Srgrimesstruct ctldebug debug5, debug6, debug7, debug8, debug9;
3561541Srgrimesstruct ctldebug debug10, debug11, debug12, debug13, debug14;
3571541Srgrimesstruct ctldebug debug15, debug16, debug17, debug18, debug19;
3581541Srgrimesstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
3591541Srgrimes	&debug0, &debug1, &debug2, &debug3, &debug4,
3601541Srgrimes	&debug5, &debug6, &debug7, &debug8, &debug9,
3611541Srgrimes	&debug10, &debug11, &debug12, &debug13, &debug14,
3621541Srgrimes	&debug15, &debug16, &debug17, &debug18, &debug19,
3631541Srgrimes};
3641541Srgrimesint
3651541Srgrimesdebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
3661541Srgrimes	int *name;
3671541Srgrimes	u_int namelen;
3681541Srgrimes	void *oldp;
3691541Srgrimes	size_t *oldlenp;
3701541Srgrimes	void *newp;
3711541Srgrimes	size_t newlen;
3721541Srgrimes	struct proc *p;
3731541Srgrimes{
3741541Srgrimes	struct ctldebug *cdp;
3751541Srgrimes
3761541Srgrimes	/* all sysctl names at this level are name and field */
3771541Srgrimes	if (namelen != 2)
3781541Srgrimes		return (ENOTDIR);		/* overloaded */
3791541Srgrimes	cdp = debugvars[name[0]];
3801541Srgrimes	if (cdp->debugname == 0)
3811541Srgrimes		return (EOPNOTSUPP);
3821541Srgrimes	switch (name[1]) {
3831541Srgrimes	case CTL_DEBUG_NAME:
3841541Srgrimes		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
3851541Srgrimes	case CTL_DEBUG_VALUE:
3861541Srgrimes		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
3871541Srgrimes	default:
3881541Srgrimes		return (EOPNOTSUPP);
3891541Srgrimes	}
3901541Srgrimes	/* NOTREACHED */
3911541Srgrimes}
3921541Srgrimes#endif /* DEBUG */
3931541Srgrimes
3941541Srgrimes/*
3951541Srgrimes * Validate parameters and get old / set new parameters
3961541Srgrimes * for an integer-valued sysctl function.
3971541Srgrimes */
3981549Srgrimesint
3991541Srgrimessysctl_int(oldp, oldlenp, newp, newlen, valp)
4001541Srgrimes	void *oldp;
4011541Srgrimes	size_t *oldlenp;
4021541Srgrimes	void *newp;
4031541Srgrimes	size_t newlen;
4041541Srgrimes	int *valp;
4051541Srgrimes{
4061541Srgrimes	int error = 0;
4071541Srgrimes
4081541Srgrimes	if (oldp && *oldlenp < sizeof(int))
4091541Srgrimes		return (ENOMEM);
4101541Srgrimes	if (newp && newlen != sizeof(int))
4111541Srgrimes		return (EINVAL);
4121541Srgrimes	*oldlenp = sizeof(int);
4131541Srgrimes	if (oldp)
4141541Srgrimes		error = copyout(valp, oldp, sizeof(int));
4151541Srgrimes	if (error == 0 && newp)
4161541Srgrimes		error = copyin(newp, valp, sizeof(int));
4171541Srgrimes	return (error);
4181541Srgrimes}
4191541Srgrimes
4201541Srgrimes/*
4211541Srgrimes * As above, but read-only.
4221541Srgrimes */
4231549Srgrimesint
4241541Srgrimessysctl_rdint(oldp, oldlenp, newp, val)
4251541Srgrimes	void *oldp;
4261541Srgrimes	size_t *oldlenp;
4271541Srgrimes	void *newp;
4281541Srgrimes	int val;
4291541Srgrimes{
4301541Srgrimes	int error = 0;
4311541Srgrimes
4321541Srgrimes	if (oldp && *oldlenp < sizeof(int))
4331541Srgrimes		return (ENOMEM);
4341541Srgrimes	if (newp)
4351541Srgrimes		return (EPERM);
4361541Srgrimes	*oldlenp = sizeof(int);
4371541Srgrimes	if (oldp)
4381541Srgrimes		error = copyout((caddr_t)&val, oldp, sizeof(int));
4391541Srgrimes	return (error);
4401541Srgrimes}
4411541Srgrimes
4421541Srgrimes/*
4431541Srgrimes * Validate parameters and get old / set new parameters
4441541Srgrimes * for a string-valued sysctl function.
4451541Srgrimes */
4461549Srgrimesint
4471541Srgrimessysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
4481541Srgrimes	void *oldp;
4491541Srgrimes	size_t *oldlenp;
4501541Srgrimes	void *newp;
4511541Srgrimes	size_t newlen;
4521541Srgrimes	char *str;
4531541Srgrimes	int maxlen;
4541541Srgrimes{
4551541Srgrimes	int len, error = 0;
4561541Srgrimes
4571541Srgrimes	len = strlen(str) + 1;
4581541Srgrimes	if (oldp && *oldlenp < len)
4591541Srgrimes		return (ENOMEM);
4601541Srgrimes	if (newp && newlen >= maxlen)
4611541Srgrimes		return (EINVAL);
4621541Srgrimes	if (oldp) {
4631541Srgrimes		*oldlenp = len;
4641541Srgrimes		error = copyout(str, oldp, len);
4651541Srgrimes	}
4661541Srgrimes	if (error == 0 && newp) {
4671541Srgrimes		error = copyin(newp, str, newlen);
4681541Srgrimes		str[newlen] = 0;
4691541Srgrimes	}
4701541Srgrimes	return (error);
4711541Srgrimes}
4721541Srgrimes
4731541Srgrimes/*
4741541Srgrimes * As above, but read-only.
4751541Srgrimes */
4761549Srgrimesint
4771541Srgrimessysctl_rdstring(oldp, oldlenp, newp, str)
4781541Srgrimes	void *oldp;
4791541Srgrimes	size_t *oldlenp;
4801541Srgrimes	void *newp;
4811541Srgrimes	char *str;
4821541Srgrimes{
4831541Srgrimes	int len, error = 0;
4841541Srgrimes
4851541Srgrimes	len = strlen(str) + 1;
4861541Srgrimes	if (oldp && *oldlenp < len)
4871541Srgrimes		return (ENOMEM);
4881541Srgrimes	if (newp)
4891541Srgrimes		return (EPERM);
4901541Srgrimes	*oldlenp = len;
4911541Srgrimes	if (oldp)
4921541Srgrimes		error = copyout(str, oldp, len);
4931541Srgrimes	return (error);
4941541Srgrimes}
4951541Srgrimes
4961541Srgrimes/*
4971541Srgrimes * Validate parameters and get old / set new parameters
4981541Srgrimes * for a structure oriented sysctl function.
4991541Srgrimes */
5001549Srgrimesint
5011541Srgrimessysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
5021541Srgrimes	void *oldp;
5031541Srgrimes	size_t *oldlenp;
5041541Srgrimes	void *newp;
5051541Srgrimes	size_t newlen;
5061541Srgrimes	void *sp;
5071541Srgrimes	int len;
5081541Srgrimes{
5091541Srgrimes	int error = 0;
5101541Srgrimes
5111541Srgrimes	if (oldp && *oldlenp < len)
5121541Srgrimes		return (ENOMEM);
5131541Srgrimes	if (newp && newlen > len)
5141541Srgrimes		return (EINVAL);
5151541Srgrimes	if (oldp) {
5161541Srgrimes		*oldlenp = len;
5171541Srgrimes		error = copyout(sp, oldp, len);
5181541Srgrimes	}
5191541Srgrimes	if (error == 0 && newp)
5201541Srgrimes		error = copyin(newp, sp, len);
5211541Srgrimes	return (error);
5221541Srgrimes}
5231541Srgrimes
5241541Srgrimes/*
5251541Srgrimes * Validate parameters and get old parameters
5261541Srgrimes * for a structure oriented sysctl function.
5271541Srgrimes */
5281549Srgrimesint
5291541Srgrimessysctl_rdstruct(oldp, oldlenp, newp, sp, len)
5301541Srgrimes	void *oldp;
5311541Srgrimes	size_t *oldlenp;
5321541Srgrimes	void *newp, *sp;
5331541Srgrimes	int len;
5341541Srgrimes{
5351541Srgrimes	int error = 0;
5361541Srgrimes
5371541Srgrimes	if (oldp && *oldlenp < len)
5381541Srgrimes		return (ENOMEM);
5391541Srgrimes	if (newp)
5401541Srgrimes		return (EPERM);
5411541Srgrimes	*oldlenp = len;
5421541Srgrimes	if (oldp)
5431541Srgrimes		error = copyout(sp, oldp, len);
5441541Srgrimes	return (error);
5451541Srgrimes}
5461541Srgrimes
5471541Srgrimes/*
5481541Srgrimes * Get file structures.
5491541Srgrimes */
5501549Srgrimesint
5511541Srgrimessysctl_file(where, sizep)
5521541Srgrimes	char *where;
5531541Srgrimes	size_t *sizep;
5541541Srgrimes{
5551541Srgrimes	int buflen, error;
5561541Srgrimes	struct file *fp;
5571541Srgrimes	char *start = where;
5581541Srgrimes
5591541Srgrimes	buflen = *sizep;
5601541Srgrimes	if (where == NULL) {
5611541Srgrimes		/*
5621541Srgrimes		 * overestimate by 10 files
5631541Srgrimes		 */
5641541Srgrimes		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
5651541Srgrimes		return (0);
5661541Srgrimes	}
5671541Srgrimes
5681541Srgrimes	/*
5691541Srgrimes	 * first copyout filehead
5701541Srgrimes	 */
5711541Srgrimes	if (buflen < sizeof(filehead)) {
5721541Srgrimes		*sizep = 0;
5731541Srgrimes		return (0);
5741541Srgrimes	}
5753308Sphk	error = copyout((caddr_t)&filehead, where, sizeof(filehead));
5763308Sphk	if (error)
5771541Srgrimes		return (error);
5781541Srgrimes	buflen -= sizeof(filehead);
5791541Srgrimes	where += sizeof(filehead);
5801541Srgrimes
5811541Srgrimes	/*
5821541Srgrimes	 * followed by an array of file structures
5831541Srgrimes	 */
5841541Srgrimes	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
5851541Srgrimes		if (buflen < sizeof(struct file)) {
5861541Srgrimes			*sizep = where - start;
5871541Srgrimes			return (ENOMEM);
5881541Srgrimes		}
5893308Sphk		error = copyout((caddr_t)fp, where, sizeof (struct file));
5903308Sphk		if (error)
5911541Srgrimes			return (error);
5921541Srgrimes		buflen -= sizeof(struct file);
5931541Srgrimes		where += sizeof(struct file);
5941541Srgrimes	}
5951541Srgrimes	*sizep = where - start;
5961541Srgrimes	return (0);
5971541Srgrimes}
5981541Srgrimes
5991541Srgrimes/*
6001541Srgrimes * try over estimating by 5 procs
6011541Srgrimes */
6021541Srgrimes#define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
6031541Srgrimes
6041549Srgrimesint
6051541Srgrimessysctl_doproc(name, namelen, where, sizep)
6061541Srgrimes	int *name;
6071541Srgrimes	u_int namelen;
6081541Srgrimes	char *where;
6091541Srgrimes	size_t *sizep;
6101541Srgrimes{
6111541Srgrimes	register struct proc *p;
6121541Srgrimes	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
6131541Srgrimes	register int needed = 0;
6141541Srgrimes	int buflen = where != NULL ? *sizep : 0;
6151541Srgrimes	int doingzomb;
6161541Srgrimes	struct eproc eproc;
6171541Srgrimes	int error = 0;
6181541Srgrimes
6191541Srgrimes	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
6201541Srgrimes		return (EINVAL);
6211541Srgrimes	p = (struct proc *)allproc;
6221541Srgrimes	doingzomb = 0;
6231541Srgrimesagain:
6241541Srgrimes	for (; p != NULL; p = p->p_next) {
6251541Srgrimes		/*
6261541Srgrimes		 * Skip embryonic processes.
6271541Srgrimes		 */
6281541Srgrimes		if (p->p_stat == SIDL)
6291541Srgrimes			continue;
6301541Srgrimes		/*
6311541Srgrimes		 * TODO - make more efficient (see notes below).
6321541Srgrimes		 * do by session.
6331541Srgrimes		 */
6341541Srgrimes		switch (name[0]) {
6351541Srgrimes
6361541Srgrimes		case KERN_PROC_PID:
6371541Srgrimes			/* could do this with just a lookup */
6381541Srgrimes			if (p->p_pid != (pid_t)name[1])
6391541Srgrimes				continue;
6401541Srgrimes			break;
6411541Srgrimes
6421541Srgrimes		case KERN_PROC_PGRP:
6431541Srgrimes			/* could do this by traversing pgrp */
6441541Srgrimes			if (p->p_pgrp->pg_id != (pid_t)name[1])
6451541Srgrimes				continue;
6461541Srgrimes			break;
6471541Srgrimes
6481541Srgrimes		case KERN_PROC_TTY:
6491541Srgrimes			if ((p->p_flag & P_CONTROLT) == 0 ||
6501541Srgrimes			    p->p_session->s_ttyp == NULL ||
6511541Srgrimes			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
6521541Srgrimes				continue;
6531541Srgrimes			break;
6541541Srgrimes
6551541Srgrimes		case KERN_PROC_UID:
6561541Srgrimes			if (p->p_ucred->cr_uid != (uid_t)name[1])
6571541Srgrimes				continue;
6581541Srgrimes			break;
6591541Srgrimes
6601541Srgrimes		case KERN_PROC_RUID:
6611541Srgrimes			if (p->p_cred->p_ruid != (uid_t)name[1])
6621541Srgrimes				continue;
6631541Srgrimes			break;
6641541Srgrimes		}
6651541Srgrimes		if (buflen >= sizeof(struct kinfo_proc)) {
6661541Srgrimes			fill_eproc(p, &eproc);
6673308Sphk			error = copyout((caddr_t)p, &dp->kp_proc,
6683308Sphk			    sizeof(struct proc));
6693308Sphk			if (error)
6701541Srgrimes				return (error);
6713308Sphk			error = copyout((caddr_t)&eproc, &dp->kp_eproc,
6723308Sphk			    sizeof(eproc));
6733308Sphk			if (error)
6741541Srgrimes				return (error);
6751541Srgrimes			dp++;
6761541Srgrimes			buflen -= sizeof(struct kinfo_proc);
6771541Srgrimes		}
6781541Srgrimes		needed += sizeof(struct kinfo_proc);
6791541Srgrimes	}
6801541Srgrimes	if (doingzomb == 0) {
6811541Srgrimes		p = zombproc;
6821541Srgrimes		doingzomb++;
6831541Srgrimes		goto again;
6841541Srgrimes	}
6851541Srgrimes	if (where != NULL) {
6861541Srgrimes		*sizep = (caddr_t)dp - where;
6871541Srgrimes		if (needed > *sizep)
6881541Srgrimes			return (ENOMEM);
6891541Srgrimes	} else {
6901541Srgrimes		needed += KERN_PROCSLOP;
6911541Srgrimes		*sizep = needed;
6921541Srgrimes	}
6931541Srgrimes	return (0);
6941541Srgrimes}
6951541Srgrimes
6961541Srgrimes/*
6971541Srgrimes * Fill in an eproc structure for the specified process.
6981541Srgrimes */
6991541Srgrimesvoid
7001541Srgrimesfill_eproc(p, ep)
7011541Srgrimes	register struct proc *p;
7021541Srgrimes	register struct eproc *ep;
7031541Srgrimes{
7041541Srgrimes	register struct tty *tp;
7051541Srgrimes
7061541Srgrimes	ep->e_paddr = p;
7071541Srgrimes	ep->e_sess = p->p_pgrp->pg_session;
7081541Srgrimes	ep->e_pcred = *p->p_cred;
7091541Srgrimes	ep->e_ucred = *p->p_ucred;
7101541Srgrimes	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
7111541Srgrimes		ep->e_vm.vm_rssize = 0;
7121541Srgrimes		ep->e_vm.vm_tsize = 0;
7131541Srgrimes		ep->e_vm.vm_dsize = 0;
7141541Srgrimes		ep->e_vm.vm_ssize = 0;
7151541Srgrimes#ifndef sparc
7161541Srgrimes		/* ep->e_vm.vm_pmap = XXX; */
7171541Srgrimes#endif
7181541Srgrimes	} else {
7191541Srgrimes		register struct vmspace *vm = p->p_vmspace;
7201541Srgrimes
7211541Srgrimes#ifdef pmap_resident_count
7221541Srgrimes		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
7231541Srgrimes#else
7241541Srgrimes		ep->e_vm.vm_rssize = vm->vm_rssize;
7251541Srgrimes#endif
7261541Srgrimes		ep->e_vm.vm_tsize = vm->vm_tsize;
7271541Srgrimes		ep->e_vm.vm_dsize = vm->vm_dsize;
7281541Srgrimes		ep->e_vm.vm_ssize = vm->vm_ssize;
7291541Srgrimes#ifndef sparc
7301541Srgrimes		ep->e_vm.vm_pmap = vm->vm_pmap;
7311541Srgrimes#endif
7321541Srgrimes	}
7331541Srgrimes	if (p->p_pptr)
7341541Srgrimes		ep->e_ppid = p->p_pptr->p_pid;
7351541Srgrimes	else
7361541Srgrimes		ep->e_ppid = 0;
7371541Srgrimes	ep->e_pgid = p->p_pgrp->pg_id;
7381541Srgrimes	ep->e_jobc = p->p_pgrp->pg_jobc;
7391541Srgrimes	if ((p->p_flag & P_CONTROLT) &&
7401541Srgrimes	     (tp = ep->e_sess->s_ttyp)) {
7411541Srgrimes		ep->e_tdev = tp->t_dev;
7421541Srgrimes		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
7431541Srgrimes		ep->e_tsess = tp->t_session;
7441541Srgrimes	} else
7451541Srgrimes		ep->e_tdev = NODEV;
7461541Srgrimes	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
7471541Srgrimes	if (SESS_LEADER(p))
7481541Srgrimes		ep->e_flag |= EPROC_SLEADER;
7491541Srgrimes	if (p->p_wmesg)
7501541Srgrimes		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
7511541Srgrimes	ep->e_xsize = ep->e_xrssize = 0;
7521541Srgrimes	ep->e_xccount = ep->e_xswrss = 0;
7531541Srgrimes}
7541541Srgrimes
7551541Srgrimes#ifdef COMPAT_43
7561541Srgrimes#include <sys/socket.h>
7571541Srgrimes#define	KINFO_PROC		(0<<8)
7581541Srgrimes#define	KINFO_RT		(1<<8)
7591541Srgrimes#define	KINFO_VNODE		(2<<8)
7601541Srgrimes#define	KINFO_FILE		(3<<8)
7611541Srgrimes#define	KINFO_METER		(4<<8)
7621541Srgrimes#define	KINFO_LOADAVG		(5<<8)
7631541Srgrimes#define	KINFO_CLOCKRATE		(6<<8)
7641541Srgrimes
7651541Srgrimesstruct getkerninfo_args {
7661541Srgrimes	int	op;
7671541Srgrimes	char	*where;
7681541Srgrimes	int	*size;
7691541Srgrimes	int	arg;
7701541Srgrimes};
7711541Srgrimes
7721549Srgrimesint
7731541Srgrimesogetkerninfo(p, uap, retval)
7741541Srgrimes	struct proc *p;
7751541Srgrimes	register struct getkerninfo_args *uap;
7761541Srgrimes	int *retval;
7771541Srgrimes{
7781541Srgrimes	int error, name[5];
7791541Srgrimes	u_int size;
7801541Srgrimes
7811541Srgrimes	if (uap->size &&
7821541Srgrimes	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
7831541Srgrimes		return (error);
7841541Srgrimes
7851541Srgrimes	switch (uap->op & 0xff00) {
7861541Srgrimes
7871541Srgrimes	case KINFO_RT:
7881541Srgrimes		name[0] = PF_ROUTE;
7891541Srgrimes		name[1] = 0;
7901541Srgrimes		name[2] = (uap->op & 0xff0000) >> 16;
7911541Srgrimes		name[3] = uap->op & 0xff;
7921541Srgrimes		name[4] = uap->arg;
7931541Srgrimes		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
7941541Srgrimes		break;
7951541Srgrimes
7961541Srgrimes	case KINFO_VNODE:
7971541Srgrimes		name[0] = KERN_VNODE;
7981541Srgrimes		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
7991541Srgrimes		break;
8001541Srgrimes
8011541Srgrimes	case KINFO_PROC:
8021541Srgrimes		name[0] = KERN_PROC;
8031541Srgrimes		name[1] = uap->op & 0xff;
8041541Srgrimes		name[2] = uap->arg;
8051541Srgrimes		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
8061541Srgrimes		break;
8071541Srgrimes
8081541Srgrimes	case KINFO_FILE:
8091541Srgrimes		name[0] = KERN_FILE;
8101541Srgrimes		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
8111541Srgrimes		break;
8121541Srgrimes
8131541Srgrimes	case KINFO_METER:
8141541Srgrimes		name[0] = VM_METER;
8151541Srgrimes		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
8161541Srgrimes		break;
8171541Srgrimes
8181541Srgrimes	case KINFO_LOADAVG:
8191541Srgrimes		name[0] = VM_LOADAVG;
8201541Srgrimes		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
8211541Srgrimes		break;
8221541Srgrimes
8231541Srgrimes	case KINFO_CLOCKRATE:
8241541Srgrimes		name[0] = KERN_CLOCKRATE;
8251541Srgrimes		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
8261541Srgrimes		break;
8271541Srgrimes
8281541Srgrimes	default:
8291541Srgrimes		return (EOPNOTSUPP);
8301541Srgrimes	}
8311541Srgrimes	if (error)
8321541Srgrimes		return (error);
8331541Srgrimes	*retval = size;
8341541Srgrimes	if (uap->size)
8351541Srgrimes		error = copyout((caddr_t)&size, (caddr_t)uap->size,
8361541Srgrimes		    sizeof(size));
8371541Srgrimes	return (error);
8381541Srgrimes}
8391541Srgrimes#endif /* COMPAT_43 */
840