kern_sysctl.c revision 1542
1231990Smp/*-
259243Sobrien * Copyright (c) 1982, 1986, 1989, 1993
359243Sobrien *	The Regents of the University of California.  All rights reserved.
459243Sobrien *
559243Sobrien * This code is derived from software contributed to Berkeley by
659243Sobrien * Mike Karels at Berkeley Software Design, Inc.
759243Sobrien *
859243Sobrien * Redistribution and use in source and binary forms, with or without
959243Sobrien * modification, are permitted provided that the following conditions
1059243Sobrien * are met:
1159243Sobrien * 1. Redistributions of source code must retain the above copyright
1259243Sobrien *    notice, this list of conditions and the following disclaimer.
1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1459243Sobrien *    notice, this list of conditions and the following disclaimer in the
1559243Sobrien *    documentation and/or other materials provided with the distribution.
1659243Sobrien * 3. All advertising materials mentioning features or use of this software
17100616Smp *    must display the following acknowledgement:
1859243Sobrien *	This product includes software developed by the University of
1959243Sobrien *	California, Berkeley and its contributors.
2059243Sobrien * 4. Neither the name of the University nor the names of its contributors
2159243Sobrien *    may be used to endorse or promote products derived from this software
2259243Sobrien *    without specific prior written permission.
2359243Sobrien *
2459243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2559243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2659243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2759243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2859243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2959243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3059243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3159243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3259243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3359243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3459243Sobrien * SUCH DAMAGE.
35231990Smp *
3659243Sobrien *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
3759243Sobrien */
3859243Sobrien
3959243Sobrien/*
40167465Smp * sysctl system call.
41167465Smp */
42167465Smp
43167465Smp#include <sys/param.h>
44167465Smp#include <sys/systm.h>
45167465Smp#include <sys/kernel.h>
46167465Smp#include <sys/malloc.h>
47167465Smp#include <sys/proc.h>
48167465Smp#include <sys/file.h>
49167465Smp#include <sys/vnode.h>
5059243Sobrien#include <sys/unistd.h>
5159243Sobrien#include <sys/buf.h>
5259243Sobrien#include <sys/ioctl.h>
5359243Sobrien#include <sys/tty.h>
5459243Sobrien#include <vm/vm.h>
5559243Sobrien#include <sys/sysctl.h>
5659243Sobrien
5759243Sobriensysctlfn kern_sysctl;
5859243Sobriensysctlfn hw_sysctl;
5959243Sobrien#ifdef DEBUG
6059243Sobriensysctlfn debug_sysctl;
61167465Smp#endif
6259243Sobrienextern sysctlfn vm_sysctl;
63167465Smpextern sysctlfn fs_sysctl;
6459243Sobrienextern sysctlfn net_sysctl;
6559243Sobrienextern sysctlfn cpu_sysctl;
6659243Sobrien
67167465Smp/*
68167465Smp * Locking and stats
69167465Smp */
70167465Smpstatic struct sysctl_lock {
7159243Sobrien	int	sl_lock;
7259243Sobrien	int	sl_want;
73167465Smp	int	sl_locked;
74167465Smp} memlock;
7559243Sobrien
76167465Smpstruct sysctl_args {
77167465Smp	int	*name;
78167465Smp	u_int	namelen;
79167465Smp	void	*old;
80167465Smp	size_t	*oldlenp;
81167465Smp	void	*new;
8259243Sobrien	size_t	newlen;
8359243Sobrien};
84167465Smp
85167465Smpint
8659243Sobrien__sysctl(p, uap, retval)
87145479Smp	struct proc *p;
88145479Smp	register struct sysctl_args *uap;
8959243Sobrien	int *retval;
9059243Sobrien{
9159243Sobrien	int error, dolock = 1;
9259243Sobrien	u_int savelen, oldlen = 0;
9359243Sobrien	sysctlfn *fn;
9459243Sobrien	int name[CTL_MAXNAME];
9559243Sobrien
9659243Sobrien	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
9759243Sobrien		return (error);
9859243Sobrien	/*
9959243Sobrien	 * all top-level sysctl names are non-terminal
10059243Sobrien	 */
10159243Sobrien	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
10259243Sobrien		return (EINVAL);
10359243Sobrien	if (error = copyin(uap->name, &name, uap->namelen * sizeof(int)))
10459243Sobrien		return (error);
10559243Sobrien
10659243Sobrien	switch (name[0]) {
10759243Sobrien	case CTL_KERN:
10859243Sobrien		fn = kern_sysctl;
10959243Sobrien		if (name[2] != KERN_VNODE)	/* XXX */
11059243Sobrien			dolock = 0;
11159243Sobrien		break;
11259243Sobrien	case CTL_HW:
11359243Sobrien		fn = hw_sysctl;
114167465Smp		break;
115167465Smp	case CTL_VM:
116167465Smp		fn = vm_sysctl;
11759243Sobrien		break;
11859243Sobrien	case CTL_NET:
11959243Sobrien		fn = net_sysctl;
12059243Sobrien		break;
12159243Sobrien#ifdef notyet
122167465Smp	case CTL_FS:
123167465Smp		fn = fs_sysctl;
12459243Sobrien		break;
12559243Sobrien#endif
12659243Sobrien	case CTL_MACHDEP:
127167465Smp		fn = cpu_sysctl;
12859243Sobrien		break;
129167465Smp#ifdef DEBUG
130167465Smp	case CTL_DEBUG:
131167465Smp		fn = debug_sysctl;
132167465Smp		break;
133167465Smp#endif
134167465Smp	default:
135167465Smp		return (EOPNOTSUPP);
136167465Smp	}
137167465Smp
138145479Smp	if (uap->oldlenp &&
13959243Sobrien	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
140145479Smp		return (error);
14159243Sobrien	if (uap->old != NULL) {
14259243Sobrien		if (!useracc(uap->old, oldlen, B_WRITE))
143167465Smp			return (EFAULT);
14459243Sobrien		while (memlock.sl_lock) {
14559243Sobrien			memlock.sl_want = 1;
14659243Sobrien			sleep((caddr_t)&memlock, PRIBIO+1);
147167465Smp			memlock.sl_locked++;
14859243Sobrien		}
149167465Smp		memlock.sl_lock = 1;
150167465Smp		if (dolock)
15159243Sobrien			vslock(uap->old, oldlen);
15259243Sobrien		savelen = oldlen;
15359243Sobrien	}
154167465Smp	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
15559243Sobrien	    uap->new, uap->newlen, p);
15659243Sobrien	if (uap->old != NULL) {
15759243Sobrien		if (dolock)
158167465Smp			vsunlock(uap->old, savelen, B_WRITE);
15959243Sobrien		memlock.sl_lock = 0;
160167465Smp		if (memlock.sl_want) {
16159243Sobrien			memlock.sl_want = 0;
16259243Sobrien			wakeup((caddr_t)&memlock);
16359243Sobrien		}
16459243Sobrien	}
16559243Sobrien	if (error)
16659243Sobrien		return (error);
16759243Sobrien	if (uap->oldlenp)
16859243Sobrien		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
169167465Smp	*retval = oldlen;
17059243Sobrien	return (0);
17159243Sobrien}
17259243Sobrien
17359243Sobrien/*
17459243Sobrien * Attributes stored in the kernel.
17559243Sobrien */
17659243Sobrienchar hostname[MAXHOSTNAMELEN];
177167465Smpint hostnamelen;
178167465Smplong hostid;
17959243Sobrienint securelevel;
180167465Smp
18159243Sobrien/*
18259243Sobrien * kernel related system variables.
18359243Sobrien */
184167465Smpkern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
18559243Sobrien	int *name;
186145479Smp	u_int namelen;
18759243Sobrien	void *oldp;
18859243Sobrien	size_t *oldlenp;
189167465Smp	void *newp;
19059243Sobrien	size_t newlen;
191167465Smp	struct proc *p;
19259243Sobrien{
19359243Sobrien	int error, level, inthostid;
19459243Sobrien	extern char ostype[], osrelease[], version[];
19559243Sobrien
19659243Sobrien	/* all sysctl names at this level are terminal */
19759243Sobrien	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
19859243Sobrien		return (ENOTDIR);		/* overloaded */
19959243Sobrien
20059243Sobrien	switch (name[0]) {
20159243Sobrien	case KERN_OSTYPE:
20259243Sobrien		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
20359243Sobrien	case KERN_OSRELEASE:
20459243Sobrien		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
20559243Sobrien	case KERN_OSREV:
20659243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
20759243Sobrien	case KERN_VERSION:
20859243Sobrien		return (sysctl_rdstring(oldp, oldlenp, newp, version));
209167465Smp	case KERN_MAXVNODES:
21059243Sobrien		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
21159243Sobrien	case KERN_MAXPROC:
21259243Sobrien		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
21359243Sobrien	case KERN_MAXFILES:
21459243Sobrien		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
21559243Sobrien	case KERN_ARGMAX:
21659243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
21759243Sobrien	case KERN_SECURELVL:
21859243Sobrien		level = securelevel;
21959243Sobrien		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
22059243Sobrien		    newp == NULL)
22159243Sobrien			return (error);
22259243Sobrien		if (level < securelevel && p->p_pid != 1)
22359243Sobrien			return (EPERM);
22459243Sobrien		securelevel = level;
22559243Sobrien		return (0);
226167465Smp	case KERN_HOSTNAME:
22759243Sobrien		error = sysctl_string(oldp, oldlenp, newp, newlen,
228167465Smp		    hostname, sizeof(hostname));
229145479Smp		if (newp && !error)
23059243Sobrien			hostnamelen = newlen;
23159243Sobrien		return (error);
23259243Sobrien	case KERN_HOSTID:
23359243Sobrien		inthostid = hostid;  /* XXX assumes sizeof long <= sizeof int */
23459243Sobrien		error =  sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
23559243Sobrien		hostid = inthostid;
23659243Sobrien		return (error);
23759243Sobrien	case KERN_CLOCKRATE:
23859243Sobrien		return (sysctl_clockrate(oldp, oldlenp));
23959243Sobrien	case KERN_BOOTTIME:
24059243Sobrien		return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
24159243Sobrien		    sizeof(struct timeval)));
24259243Sobrien	case KERN_VNODE:
24359243Sobrien		return (sysctl_vnode(oldp, oldlenp));
24459243Sobrien	case KERN_PROC:
24559243Sobrien		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
24659243Sobrien	case KERN_FILE:
24759243Sobrien		return (sysctl_file(oldp, oldlenp));
24859243Sobrien#ifdef GPROF
24959243Sobrien	case KERN_PROF:
25059243Sobrien		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
25159243Sobrien		    newp, newlen));
25259243Sobrien#endif
25359243Sobrien	case KERN_POSIX1:
25459243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
25559243Sobrien	case KERN_NGROUPS:
25659243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
25759243Sobrien	case KERN_JOB_CONTROL:
25859243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, 1));
25959243Sobrien	case KERN_SAVED_IDS:
26059243Sobrien#ifdef _POSIX_SAVED_IDS
26159243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, 1));
26259243Sobrien#else
26359243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, 0));
26459243Sobrien#endif
265167465Smp	default:
26659243Sobrien		return (EOPNOTSUPP);
26759243Sobrien	}
26859243Sobrien	/* NOTREACHED */
26959243Sobrien}
27059243Sobrien
27159243Sobrien/*
27259243Sobrien * hardware related system variables.
273167465Smp */
27459243Sobrienhw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
27559243Sobrien	int *name;
27659243Sobrien	u_int namelen;
27759243Sobrien	void *oldp;
27859243Sobrien	size_t *oldlenp;
27959243Sobrien	void *newp;
28059243Sobrien	size_t newlen;
28159243Sobrien	struct proc *p;
28259243Sobrien{
28359243Sobrien	extern char machine[], cpu_model[];
28459243Sobrien
28559243Sobrien	/* all sysctl names at this level are terminal */
28659243Sobrien	if (namelen != 1)
28759243Sobrien		return (ENOTDIR);		/* overloaded */
28859243Sobrien
28959243Sobrien	switch (name[0]) {
29059243Sobrien	case HW_MACHINE:
29159243Sobrien		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
29259243Sobrien	case HW_MODEL:
29359243Sobrien		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
294167465Smp	case HW_NCPU:
29559243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
296167465Smp	case HW_BYTEORDER:
297145479Smp		return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
29859243Sobrien	case HW_PHYSMEM:
29959243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
30059243Sobrien	case HW_USERMEM:
30159243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp,
30259243Sobrien		    ctob(physmem - cnt.v_wire_count)));
30359243Sobrien	case HW_PAGESIZE:
30459243Sobrien		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
30559243Sobrien	default:
30659243Sobrien		return (EOPNOTSUPP);
30759243Sobrien	}
30859243Sobrien	/* NOTREACHED */
30959243Sobrien}
31059243Sobrien
31159243Sobrien#ifdef DEBUG
31259243Sobrien/*
31359243Sobrien * Debugging related system variables.
31459243Sobrien */
31559243Sobrienstruct ctldebug debug0, debug1, debug2, debug3, debug4;
316167465Smpstruct ctldebug debug5, debug6, debug7, debug8, debug9;
31759243Sobrienstruct ctldebug debug10, debug11, debug12, debug13, debug14;
31859243Sobrienstruct ctldebug debug15, debug16, debug17, debug18, debug19;
31959243Sobrienstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
32059243Sobrien	&debug0, &debug1, &debug2, &debug3, &debug4,
32159243Sobrien	&debug5, &debug6, &debug7, &debug8, &debug9,
32259243Sobrien	&debug10, &debug11, &debug12, &debug13, &debug14,
32359243Sobrien	&debug15, &debug16, &debug17, &debug18, &debug19,
32459243Sobrien};
32559243Sobrienint
32659243Sobriendebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
32759243Sobrien	int *name;
32859243Sobrien	u_int namelen;
32959243Sobrien	void *oldp;
33059243Sobrien	size_t *oldlenp;
33159243Sobrien	void *newp;
33259243Sobrien	size_t newlen;
33359243Sobrien	struct proc *p;
33459243Sobrien{
33559243Sobrien	struct ctldebug *cdp;
336167465Smp
33759243Sobrien	/* all sysctl names at this level are name and field */
338167465Smp	if (namelen != 2)
339145479Smp		return (ENOTDIR);		/* overloaded */
340145479Smp	cdp = debugvars[name[0]];
34159243Sobrien	if (cdp->debugname == 0)
34259243Sobrien		return (EOPNOTSUPP);
34359243Sobrien	switch (name[1]) {
34459243Sobrien	case CTL_DEBUG_NAME:
34559243Sobrien		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
34659243Sobrien	case CTL_DEBUG_VALUE:
34759243Sobrien		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
34859243Sobrien	default:
34959243Sobrien		return (EOPNOTSUPP);
35059243Sobrien	}
35159243Sobrien	/* NOTREACHED */
35259243Sobrien}
35359243Sobrien#endif /* DEBUG */
35459243Sobrien
35559243Sobrien/*
35659243Sobrien * Validate parameters and get old / set new parameters
357167465Smp * for an integer-valued sysctl function.
35859243Sobrien */
35959243Sobriensysctl_int(oldp, oldlenp, newp, newlen, valp)
36059243Sobrien	void *oldp;
36159243Sobrien	size_t *oldlenp;
36259243Sobrien	void *newp;
36359243Sobrien	size_t newlen;
36459243Sobrien	int *valp;
36559243Sobrien{
36659243Sobrien	int error = 0;
36759243Sobrien
36859243Sobrien	if (oldp && *oldlenp < sizeof(int))
36959243Sobrien		return (ENOMEM);
37059243Sobrien	if (newp && newlen != sizeof(int))
37159243Sobrien		return (EINVAL);
37259243Sobrien	*oldlenp = sizeof(int);
37359243Sobrien	if (oldp)
37459243Sobrien		error = copyout(valp, oldp, sizeof(int));
37559243Sobrien	if (error == 0 && newp)
37659243Sobrien		error = copyin(newp, valp, sizeof(int));
37759243Sobrien	return (error);
378167465Smp}
37959243Sobrien
380167465Smp/*
381145479Smp * As above, but read-only.
382145479Smp */
38359243Sobriensysctl_rdint(oldp, oldlenp, newp, val)
38459243Sobrien	void *oldp;
38559243Sobrien	size_t *oldlenp;
38659243Sobrien	void *newp;
38759243Sobrien	int val;
38859243Sobrien{
38959243Sobrien	int error = 0;
39059243Sobrien
39159243Sobrien	if (oldp && *oldlenp < sizeof(int))
39259243Sobrien		return (ENOMEM);
39359243Sobrien	if (newp)
39459243Sobrien		return (EPERM);
39559243Sobrien	*oldlenp = sizeof(int);
39659243Sobrien	if (oldp)
397167465Smp		error = copyout((caddr_t)&val, oldp, sizeof(int));
39859243Sobrien	return (error);
39959243Sobrien}
40059243Sobrien
40159243Sobrien/*
40259243Sobrien * Validate parameters and get old / set new parameters
40359243Sobrien * for a string-valued sysctl function.
40459243Sobrien */
40559243Sobriensysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
40659243Sobrien	void *oldp;
40759243Sobrien	size_t *oldlenp;
40859243Sobrien	void *newp;
40959243Sobrien	size_t newlen;
41059243Sobrien	char *str;
41159243Sobrien	int maxlen;
41259243Sobrien{
41359243Sobrien	int len, error = 0;
41459243Sobrien
41559243Sobrien	len = strlen(str) + 1;
41659243Sobrien	if (oldp && *oldlenp < len)
41759243Sobrien		return (ENOMEM);
41859243Sobrien	if (newp && newlen >= maxlen)
419167465Smp		return (EINVAL);
42059243Sobrien	if (oldp) {
421167465Smp		*oldlenp = len;
422145479Smp		error = copyout(str, oldp, len);
423145479Smp	}
42459243Sobrien	if (error == 0 && newp) {
42559243Sobrien		error = copyin(newp, str, newlen);
42659243Sobrien		str[newlen] = 0;
42759243Sobrien	}
42859243Sobrien	return (error);
42959243Sobrien}
43059243Sobrien
43159243Sobrien/*
43259243Sobrien * As above, but read-only.
43359243Sobrien */
43459243Sobriensysctl_rdstring(oldp, oldlenp, newp, str)
43559243Sobrien	void *oldp;
43659243Sobrien	size_t *oldlenp;
43759243Sobrien	void *newp;
43859243Sobrien	char *str;
43959243Sobrien{
440167465Smp	int len, error = 0;
44159243Sobrien
44259243Sobrien	len = strlen(str) + 1;
44359243Sobrien	if (oldp && *oldlenp < len)
44459243Sobrien		return (ENOMEM);
44559243Sobrien	if (newp)
44659243Sobrien		return (EPERM);
44759243Sobrien	*oldlenp = len;
44859243Sobrien	if (oldp)
44959243Sobrien		error = copyout(str, oldp, len);
45059243Sobrien	return (error);
45159243Sobrien}
45259243Sobrien
45359243Sobrien/*
45459243Sobrien * Validate parameters and get old / set new parameters
45559243Sobrien * for a structure oriented sysctl function.
45659243Sobrien */
45759243Sobriensysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
45859243Sobrien	void *oldp;
45959243Sobrien	size_t *oldlenp;
460167465Smp	void *newp;
46159243Sobrien	size_t newlen;
46259243Sobrien	void *sp;
46359243Sobrien	int len;
46459243Sobrien{
46559243Sobrien	int error = 0;
46659243Sobrien
46759243Sobrien	if (oldp && *oldlenp < len)
46859243Sobrien		return (ENOMEM);
46959243Sobrien	if (newp && newlen > len)
47059243Sobrien		return (EINVAL);
471167465Smp	if (oldp) {
47259243Sobrien		*oldlenp = len;
473167465Smp		error = copyout(sp, oldp, len);
474167465Smp	}
475145479Smp	if (error == 0 && newp)
476145479Smp		error = copyin(newp, sp, len);
47759243Sobrien	return (error);
47859243Sobrien}
479145479Smp
48059243Sobrien/*
48159243Sobrien * Validate parameters and get old parameters
48259243Sobrien * for a structure oriented sysctl function.
48359243Sobrien */
48459243Sobriensysctl_rdstruct(oldp, oldlenp, newp, sp, len)
48559243Sobrien	void *oldp;
48659243Sobrien	size_t *oldlenp;
48759243Sobrien	void *newp, *sp;
48859243Sobrien	int len;
48959243Sobrien{
49059243Sobrien	int error = 0;
49159243Sobrien
49259243Sobrien	if (oldp && *oldlenp < len)
49359243Sobrien		return (ENOMEM);
49459243Sobrien	if (newp)
49559243Sobrien		return (EPERM);
49659243Sobrien	*oldlenp = len;
49759243Sobrien	if (oldp)
49859243Sobrien		error = copyout(sp, oldp, len);
49959243Sobrien	return (error);
50059243Sobrien}
50159243Sobrien
50259243Sobrien/*
50359243Sobrien * Get file structures.
50459243Sobrien */
50559243Sobriensysctl_file(where, sizep)
50659243Sobrien	char *where;
50759243Sobrien	size_t *sizep;
50859243Sobrien{
50959243Sobrien	int buflen, error;
51059243Sobrien	struct file *fp;
51159243Sobrien	char *start = where;
51259243Sobrien
51359243Sobrien	buflen = *sizep;
51459243Sobrien	if (where == NULL) {
51559243Sobrien		/*
51659243Sobrien		 * overestimate by 10 files
51759243Sobrien		 */
51859243Sobrien		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
51959243Sobrien		return (0);
52059243Sobrien	}
52159243Sobrien
52259243Sobrien	/*
52359243Sobrien	 * first copyout filehead
52459243Sobrien	 */
52559243Sobrien	if (buflen < sizeof(filehead)) {
52659243Sobrien		*sizep = 0;
52759243Sobrien		return (0);
52859243Sobrien	}
52959243Sobrien	if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
53059243Sobrien		return (error);
53159243Sobrien	buflen -= sizeof(filehead);
53259243Sobrien	where += sizeof(filehead);
53359243Sobrien
53459243Sobrien	/*
53559243Sobrien	 * followed by an array of file structures
53659243Sobrien	 */
53759243Sobrien	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
53859243Sobrien		if (buflen < sizeof(struct file)) {
53959243Sobrien			*sizep = where - start;
54059243Sobrien			return (ENOMEM);
54159243Sobrien		}
54259243Sobrien		if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
54359243Sobrien			return (error);
544167465Smp		buflen -= sizeof(struct file);
545167465Smp		where += sizeof(struct file);
54659243Sobrien	}
54759243Sobrien	*sizep = where - start;
54859243Sobrien	return (0);
54959243Sobrien}
55059243Sobrien
55159243Sobrien/*
55259243Sobrien * try over estimating by 5 procs
55359243Sobrien */
55459243Sobrien#define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
55559243Sobrien
55659243Sobriensysctl_doproc(name, namelen, where, sizep)
55759243Sobrien	int *name;
55859243Sobrien	u_int namelen;
55959243Sobrien	char *where;
56059243Sobrien	size_t *sizep;
56159243Sobrien{
56259243Sobrien	register struct proc *p;
56359243Sobrien	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
56459243Sobrien	register int needed = 0;
56559243Sobrien	int buflen = where != NULL ? *sizep : 0;
56659243Sobrien	int doingzomb;
56759243Sobrien	struct eproc eproc;
56859243Sobrien	int error = 0;
56959243Sobrien
57059243Sobrien	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
57159243Sobrien		return (EINVAL);
57259243Sobrien	p = (struct proc *)allproc;
57359243Sobrien	doingzomb = 0;
57459243Sobrienagain:
57559243Sobrien	for (; p != NULL; p = p->p_next) {
57659243Sobrien		/*
57759243Sobrien		 * Skip embryonic processes.
57859243Sobrien		 */
57959243Sobrien		if (p->p_stat == SIDL)
58059243Sobrien			continue;
58159243Sobrien		/*
58259243Sobrien		 * TODO - make more efficient (see notes below).
58359243Sobrien		 * do by session.
58459243Sobrien		 */
58559243Sobrien		switch (name[0]) {
58659243Sobrien
58759243Sobrien		case KERN_PROC_PID:
58859243Sobrien			/* could do this with just a lookup */
58959243Sobrien			if (p->p_pid != (pid_t)name[1])
59059243Sobrien				continue;
59159243Sobrien			break;
59259243Sobrien
59359243Sobrien		case KERN_PROC_PGRP:
59459243Sobrien			/* could do this by traversing pgrp */
59559243Sobrien			if (p->p_pgrp->pg_id != (pid_t)name[1])
59659243Sobrien				continue;
59759243Sobrien			break;
59859243Sobrien
59959243Sobrien		case KERN_PROC_TTY:
60059243Sobrien			if ((p->p_flag & P_CONTROLT) == 0 ||
60159243Sobrien			    p->p_session->s_ttyp == NULL ||
60259243Sobrien			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
60359243Sobrien				continue;
60459243Sobrien			break;
60559243Sobrien
60659243Sobrien		case KERN_PROC_UID:
60759243Sobrien			if (p->p_ucred->cr_uid != (uid_t)name[1])
60859243Sobrien				continue;
60959243Sobrien			break;
61059243Sobrien
61159243Sobrien		case KERN_PROC_RUID:
61259243Sobrien			if (p->p_cred->p_ruid != (uid_t)name[1])
61359243Sobrien				continue;
61459243Sobrien			break;
61559243Sobrien		}
61659243Sobrien		if (buflen >= sizeof(struct kinfo_proc)) {
61759243Sobrien			fill_eproc(p, &eproc);
61859243Sobrien			if (error = copyout((caddr_t)p, &dp->kp_proc,
61959243Sobrien			    sizeof(struct proc)))
62059243Sobrien				return (error);
62159243Sobrien			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
62259243Sobrien			    sizeof(eproc)))
62359243Sobrien				return (error);
62459243Sobrien			dp++;
62559243Sobrien			buflen -= sizeof(struct kinfo_proc);
62659243Sobrien		}
62759243Sobrien		needed += sizeof(struct kinfo_proc);
62859243Sobrien	}
62959243Sobrien	if (doingzomb == 0) {
63059243Sobrien		p = zombproc;
63159243Sobrien		doingzomb++;
63259243Sobrien		goto again;
63359243Sobrien	}
63459243Sobrien	if (where != NULL) {
63559243Sobrien		*sizep = (caddr_t)dp - where;
63659243Sobrien		if (needed > *sizep)
63759243Sobrien			return (ENOMEM);
63859243Sobrien	} else {
63959243Sobrien		needed += KERN_PROCSLOP;
64059243Sobrien		*sizep = needed;
64159243Sobrien	}
64259243Sobrien	return (0);
64359243Sobrien}
64459243Sobrien
64559243Sobrien/*
64659243Sobrien * Fill in an eproc structure for the specified process.
64759243Sobrien */
64859243Sobrienvoid
64959243Sobrienfill_eproc(p, ep)
650167465Smp	register struct proc *p;
65159243Sobrien	register struct eproc *ep;
652145479Smp{
65359243Sobrien	register struct tty *tp;
65459243Sobrien
65559243Sobrien	ep->e_paddr = p;
65659243Sobrien	ep->e_sess = p->p_pgrp->pg_session;
65759243Sobrien	ep->e_pcred = *p->p_cred;
65859243Sobrien	ep->e_ucred = *p->p_ucred;
65959243Sobrien	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
660167465Smp		ep->e_vm.vm_rssize = 0;
661167465Smp		ep->e_vm.vm_tsize = 0;
662167465Smp		ep->e_vm.vm_dsize = 0;
663167465Smp		ep->e_vm.vm_ssize = 0;
66459243Sobrien#ifndef sparc
66559243Sobrien		/* ep->e_vm.vm_pmap = XXX; */
66659243Sobrien#endif
667167465Smp	} else {
668167465Smp		register struct vmspace *vm = p->p_vmspace;
66959243Sobrien
67059243Sobrien#ifdef pmap_resident_count
67159243Sobrien		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
67259243Sobrien#else
67359243Sobrien		ep->e_vm.vm_rssize = vm->vm_rssize;
67459243Sobrien#endif
67559243Sobrien		ep->e_vm.vm_tsize = vm->vm_tsize;
67659243Sobrien		ep->e_vm.vm_dsize = vm->vm_dsize;
67759243Sobrien		ep->e_vm.vm_ssize = vm->vm_ssize;
67859243Sobrien#ifndef sparc
67959243Sobrien		ep->e_vm.vm_pmap = vm->vm_pmap;
680231990Smp#endif
681231990Smp	}
682231990Smp	if (p->p_pptr)
683167465Smp		ep->e_ppid = p->p_pptr->p_pid;
68459243Sobrien	else
685167465Smp		ep->e_ppid = 0;
686167465Smp	ep->e_pgid = p->p_pgrp->pg_id;
687167465Smp	ep->e_jobc = p->p_pgrp->pg_jobc;
688167465Smp	if ((p->p_flag & P_CONTROLT) &&
689167465Smp	     (tp = ep->e_sess->s_ttyp)) {
690167465Smp		ep->e_tdev = tp->t_dev;
691167465Smp		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
692167465Smp		ep->e_tsess = tp->t_session;
693167465Smp	} else
694		ep->e_tdev = NODEV;
695	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
696	if (SESS_LEADER(p))
697		ep->e_flag |= EPROC_SLEADER;
698	if (p->p_wmesg)
699		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
700	ep->e_xsize = ep->e_xrssize = 0;
701	ep->e_xccount = ep->e_xswrss = 0;
702}
703
704#ifdef COMPAT_43
705#include <sys/socket.h>
706#define	KINFO_PROC		(0<<8)
707#define	KINFO_RT		(1<<8)
708#define	KINFO_VNODE		(2<<8)
709#define	KINFO_FILE		(3<<8)
710#define	KINFO_METER		(4<<8)
711#define	KINFO_LOADAVG		(5<<8)
712#define	KINFO_CLOCKRATE		(6<<8)
713
714struct getkerninfo_args {
715	int	op;
716	char	*where;
717	int	*size;
718	int	arg;
719};
720
721ogetkerninfo(p, uap, retval)
722	struct proc *p;
723	register struct getkerninfo_args *uap;
724	int *retval;
725{
726	int error, name[5];
727	u_int size;
728
729	if (uap->size &&
730	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
731		return (error);
732
733	switch (uap->op & 0xff00) {
734
735	case KINFO_RT:
736		name[0] = PF_ROUTE;
737		name[1] = 0;
738		name[2] = (uap->op & 0xff0000) >> 16;
739		name[3] = uap->op & 0xff;
740		name[4] = uap->arg;
741		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
742		break;
743
744	case KINFO_VNODE:
745		name[0] = KERN_VNODE;
746		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
747		break;
748
749	case KINFO_PROC:
750		name[0] = KERN_PROC;
751		name[1] = uap->op & 0xff;
752		name[2] = uap->arg;
753		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
754		break;
755
756	case KINFO_FILE:
757		name[0] = KERN_FILE;
758		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
759		break;
760
761	case KINFO_METER:
762		name[0] = VM_METER;
763		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
764		break;
765
766	case KINFO_LOADAVG:
767		name[0] = VM_LOADAVG;
768		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
769		break;
770
771	case KINFO_CLOCKRATE:
772		name[0] = KERN_CLOCKRATE;
773		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
774		break;
775
776	default:
777		return (EOPNOTSUPP);
778	}
779	if (error)
780		return (error);
781	*retval = size;
782	if (uap->size)
783		error = copyout((caddr_t)&size, (caddr_t)uap->size,
784		    sizeof(size));
785	return (error);
786}
787#endif /* COMPAT_43 */
788