xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 59718)
157843Smckusick /*-
257843Smckusick  * Copyright (c) 1982, 1986, 1989, 1993 Regents of the University of California.
339963Smarc  * All rights reserved.
439963Smarc  *
557843Smckusick  * This code is derived from software contributed to Berkeley by
657843Smckusick  * Mike Karels at Berkeley Software Design, Inc.
757843Smckusick  *
844435Sbostic  * %sccs.include.redist.c%
939963Smarc  *
10*59718Sbostic  *	@(#)kern_sysctl.c	7.38 (Berkeley) 05/04/93
1139963Smarc  */
1239963Smarc 
1357843Smckusick /*
1457843Smckusick  * sysctl system call.
1557843Smckusick  */
1657843Smckusick 
1756517Sbostic #include <sys/param.h>
1857843Smckusick #include <sys/systm.h>
1957843Smckusick #include <sys/malloc.h>
2056517Sbostic #include <sys/proc.h>
2157843Smckusick #include <sys/file.h>
2259314Smckusick #include <sys/vnode.h>
2357843Smckusick #include <sys/unistd.h>
2457843Smckusick #include <sys/buf.h>
2556517Sbostic #include <sys/ioctl.h>
2656517Sbostic #include <sys/tty.h>
2756517Sbostic #include <vm/vm.h>
2859354Smckusick #include <sys/sysctl.h>
2948407Skarels 
3057843Smckusick sysctlfn kern_sysctl;
3157843Smckusick sysctlfn hw_sysctl;
3259161Smckusick #ifdef DEBUG
3359161Smckusick sysctlfn debug_sysctl;
3459161Smckusick #endif
3557843Smckusick extern sysctlfn vm_sysctl;
3657843Smckusick extern sysctlfn fs_sysctl;
3757843Smckusick extern sysctlfn net_sysctl;
3857843Smckusick extern sysctlfn cpu_sysctl;
3940068Smarc 
4057843Smckusick /*
4157843Smckusick  * Locking and stats
4257843Smckusick  */
4357843Smckusick static struct sysctl_lock {
4457843Smckusick 	int	sl_lock;
4557843Smckusick 	int	sl_want;
4657843Smckusick 	int	sl_locked;
4757843Smckusick } memlock;
4857843Smckusick 
4957843Smckusick struct sysctl_args {
5057843Smckusick 	int	*name;
5157843Smckusick 	u_int	namelen;
5257843Smckusick 	void	*old;
5358466Sbostic 	size_t	*oldlenp;
5457843Smckusick 	void	*new;
5558466Sbostic 	size_t	newlen;
5654923Storek };
5757843Smckusick 
58*59718Sbostic int
59*59718Sbostic __sysctl(p, uap, retval)
6043444Smckusick 	struct proc *p;
6157843Smckusick 	register struct sysctl_args *uap;
6243444Smckusick 	int *retval;
6343444Smckusick {
6457843Smckusick 	int error, dolock = 1;
6557843Smckusick 	u_int savelen, oldlen = 0;
6657843Smckusick 	sysctlfn *fn;
6757843Smckusick 	int name[CTL_MAXNAME];
6839963Smarc 
6957843Smckusick 	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
7057843Smckusick 		return (error);
7157843Smckusick 	/*
7257843Smckusick 	 * all top-level sysctl names are non-terminal
7357843Smckusick 	 */
7457843Smckusick 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
7557843Smckusick 		return (EINVAL);
7657843Smckusick 	if (error = copyin(uap->name, &name, uap->namelen * sizeof(int)))
7757843Smckusick 		return (error);
7839963Smarc 
7957843Smckusick 	switch (name[0]) {
8057843Smckusick 	case CTL_KERN:
8157843Smckusick 		fn = kern_sysctl;
8257843Smckusick 		if (name[2] != KERN_VNODE)	/* XXX */
8357843Smckusick 			dolock = 0;
8439963Smarc 		break;
8557843Smckusick 	case CTL_HW:
8657843Smckusick 		fn = hw_sysctl;
8740068Smarc 		break;
8857843Smckusick 	case CTL_VM:
8957843Smckusick 		fn = vm_sysctl;
9041181Smarc 		break;
9157843Smckusick 	case CTL_NET:
9257843Smckusick 		fn = net_sysctl;
9350149Smarc 		break;
9457843Smckusick #ifdef notyet
9557843Smckusick 	case CTL_FS:
9657843Smckusick 		fn = fs_sysctl;
9750909Smckusick 		break;
9857843Smckusick 	case CTL_MACHDEP:
9957843Smckusick 		fn = cpu_sysctl;
10052669Smckusick 		break;
10157843Smckusick #endif
10259161Smckusick #ifdef DEBUG
10359161Smckusick 	case CTL_DEBUG:
10459161Smckusick 		fn = debug_sysctl;
10559161Smckusick 		break;
10659161Smckusick #endif
10739963Smarc 	default:
10857843Smckusick 		return (EOPNOTSUPP);
10939963Smarc 	}
11057843Smckusick 
11157843Smckusick 	if (uap->oldlenp &&
11257843Smckusick 	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
11357843Smckusick 		return (error);
11457843Smckusick 	if (uap->old != NULL) {
11557843Smckusick 		if (!useracc(uap->old, oldlen, B_WRITE))
11657843Smckusick 			return (EFAULT);
11757843Smckusick 		while (memlock.sl_lock) {
11857843Smckusick 			memlock.sl_want = 1;
11957843Smckusick 			sleep((caddr_t)&memlock, PRIBIO+1);
12057843Smckusick 			memlock.sl_locked++;
12157843Smckusick 		}
12257843Smckusick 		memlock.sl_lock = 1;
12357843Smckusick 		if (dolock)
12457843Smckusick 			vslock(uap->old, oldlen);
12557843Smckusick 		savelen = oldlen;
12640813Smarc 	}
12757843Smckusick 	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
12858415Smckusick 	    uap->new, uap->newlen, p);
12957843Smckusick 	if (uap->old != NULL) {
13057843Smckusick 		if (dolock)
13157843Smckusick 			vsunlock(uap->old, savelen, B_WRITE);
13257843Smckusick 		memlock.sl_lock = 0;
13357843Smckusick 		if (memlock.sl_want) {
13457843Smckusick 			memlock.sl_want = 0;
13557843Smckusick 			wakeup((caddr_t)&memlock);
13657843Smckusick 		}
13740206Smarc 	}
13857843Smckusick 	if (error)
13957843Smckusick 		return (error);
14057843Smckusick 	if (uap->oldlenp)
14157843Smckusick 		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
14257843Smckusick 	*retval = oldlen;
14357843Smckusick 	return (0);
14457843Smckusick }
14540206Smarc 
14657843Smckusick /*
14757843Smckusick  * Attributes stored in the kernel.
14857843Smckusick  */
14957843Smckusick char hostname[MAXHOSTNAMELEN];
15057843Smckusick int hostnamelen;
15157843Smckusick long hostid;
15258415Smckusick int securelevel;
15357843Smckusick 
15458415Smckusick /*
15558415Smckusick  * kernel related system variables.
15658415Smckusick  */
15758415Smckusick kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
15857843Smckusick 	int *name;
15957843Smckusick 	u_int namelen;
16057843Smckusick 	void *oldp;
16158466Sbostic 	size_t *oldlenp;
16257843Smckusick 	void *newp;
16358466Sbostic 	size_t newlen;
16458415Smckusick 	struct proc *p;
16557843Smckusick {
16658415Smckusick 	int error, level;
16757843Smckusick 	extern char ostype[], osrelease[], version[];
16857843Smckusick 
16957843Smckusick 	/* all sysctl names at this level are terminal */
17059312Smckusick 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
17157843Smckusick 		return (ENOTDIR);		/* overloaded */
17257843Smckusick 
17357843Smckusick 	switch (name[0]) {
17457843Smckusick 	case KERN_OSTYPE:
17557843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
17657843Smckusick 	case KERN_OSRELEASE:
17757843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
17857843Smckusick 	case KERN_OSREV:
17957843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
18057843Smckusick 	case KERN_VERSION:
18157843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, version));
182*59718Sbostic 	case KERN_MAXVNODES:
183*59718Sbostic 		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
18457843Smckusick 	case KERN_MAXPROC:
18557843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
18657843Smckusick 	case KERN_MAXFILES:
18757843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
18857843Smckusick 	case KERN_ARGMAX:
18957843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
19058415Smckusick 	case KERN_SECURELVL:
19158415Smckusick 		level = securelevel;
19258415Smckusick 		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
19358415Smckusick 		    newp == NULL)
19458415Smckusick 			return (error);
19558415Smckusick 		if (level < securelevel && p->p_pid != 1)
19658415Smckusick 			return (EPERM);
19758415Smckusick 		securelevel = level;
19858415Smckusick 		return (0);
199*59718Sbostic 	case KERN_HOSTNAME:
200*59718Sbostic 		error = sysctl_string(oldp, oldlenp, newp, newlen,
201*59718Sbostic 		    hostname, sizeof(hostname));
202*59718Sbostic 		if (!error)
203*59718Sbostic 			hostnamelen = newlen;
204*59718Sbostic 		return (error);
205*59718Sbostic 	case KERN_HOSTID:
206*59718Sbostic 		return (sysctl_int(oldp, oldlenp, newp, newlen, &hostid));
20757843Smckusick 	case KERN_CLOCKRATE:
20857843Smckusick 		return (sysctl_clockrate(oldp, oldlenp));
20957843Smckusick 	case KERN_VNODE:
21057843Smckusick 		return (sysctl_vnode(oldp, oldlenp));
21157843Smckusick 	case KERN_PROC:
21257843Smckusick 		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
213*59718Sbostic 	case KERN_FILE:
214*59718Sbostic 		return (sysctl_file(oldp, oldlenp));
21559312Smckusick #ifdef GPROF
21659312Smckusick 	case KERN_PROF:
21759312Smckusick 		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
21859312Smckusick 		    newp, newlen));
21959312Smckusick #endif
220*59718Sbostic 	case KERN_POSIX1:
221*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
222*59718Sbostic 	case KERN_NGROUPS:
223*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
224*59718Sbostic 	case KERN_JOB_CONTROL:
225*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
226*59718Sbostic 	case KERN_SAVED_IDS:
227*59718Sbostic #ifdef _POSIX_SAVED_IDS
228*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
229*59718Sbostic #else
230*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
231*59718Sbostic #endif
232*59718Sbostic 	case KERN_LINK_MAX:
233*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, LINK_MAX));
234*59718Sbostic 	case KERN_MAX_CANON:
235*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, MAX_CANON));
236*59718Sbostic 	case KERN_MAX_INPUT:
237*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, MAX_INPUT));
238*59718Sbostic 	case KERN_NAME_MAX:
239*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, NAME_MAX));
240*59718Sbostic 	case KERN_PATH_MAX:
241*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, PATH_MAX));
242*59718Sbostic 	case KERN_PIPE_BUF:
243*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, PIPE_BUF));
244*59718Sbostic 	case KERN_CHOWN_RESTRICTED:
245*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
246*59718Sbostic 	case KERN_NO_TRUNC:
247*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
248*59718Sbostic 	case KERN_VDISABLE:
249*59718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VDISABLE));
25057843Smckusick 	default:
25157843Smckusick 		return (EOPNOTSUPP);
25252405Storek 	}
25357843Smckusick 	/* NOTREACHED */
25457843Smckusick }
25557843Smckusick 
25658415Smckusick /*
25758415Smckusick  * hardware related system variables.
25858415Smckusick  */
25958415Smckusick hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
26057843Smckusick 	int *name;
26157843Smckusick 	u_int namelen;
26257843Smckusick 	void *oldp;
26358466Sbostic 	size_t *oldlenp;
26457843Smckusick 	void *newp;
26558466Sbostic 	size_t newlen;
26658415Smckusick 	struct proc *p;
26757843Smckusick {
26857843Smckusick 	extern char machine[], cpu_model[];
26957843Smckusick 
27057843Smckusick 	/* all sysctl names at this level are terminal */
27157843Smckusick 	if (namelen != 1)
27257843Smckusick 		return (ENOTDIR);		/* overloaded */
27357843Smckusick 
27457843Smckusick 	switch (name[0]) {
27557843Smckusick 	case HW_MACHINE:
27657843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
27757843Smckusick 	case HW_MODEL:
27857843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
27957843Smckusick 	case HW_NCPU:
28057843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
28159618Smckusick 	case HW_BYTEORDER:
28259618Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
28357843Smckusick 	case HW_PHYSMEM:
28457843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
28557843Smckusick 	case HW_USERMEM:
28657843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp,
28757843Smckusick 		    ctob(physmem - cnt.v_wire_count)));
28857843Smckusick 	case HW_PAGESIZE:
28957843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
29057843Smckusick 	default:
29157843Smckusick 		return (EOPNOTSUPP);
29257843Smckusick 	}
29357843Smckusick 	/* NOTREACHED */
29457843Smckusick }
29557843Smckusick 
29659161Smckusick #ifdef DEBUG
29757843Smckusick /*
29859161Smckusick  * Debugging related system variables.
29959161Smckusick  */
30059161Smckusick struct ctldebug debug0, debug1, debug2, debug3, debug4;
30159161Smckusick struct ctldebug debug5, debug6, debug7, debug8, debug9;
30259161Smckusick struct ctldebug debug10, debug11, debug12, debug13, debug14;
30359161Smckusick struct ctldebug debug15, debug16, debug17, debug18, debug19;
30459161Smckusick static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
30559161Smckusick 	&debug0, &debug1, &debug2, &debug3, &debug4,
30659161Smckusick 	&debug5, &debug6, &debug7, &debug8, &debug9,
30759161Smckusick 	&debug10, &debug11, &debug12, &debug13, &debug14,
30859161Smckusick 	&debug15, &debug16, &debug17, &debug18, &debug19,
30959161Smckusick };
31059161Smckusick int
31159161Smckusick debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
31259161Smckusick 	int *name;
31359161Smckusick 	u_int namelen;
31459161Smckusick 	void *oldp;
31559161Smckusick 	size_t *oldlenp;
31659161Smckusick 	void *newp;
31759161Smckusick 	size_t newlen;
31859161Smckusick 	struct proc *p;
31959161Smckusick {
32059161Smckusick 	struct ctldebug *cdp;
32159161Smckusick 
32259161Smckusick 	/* all sysctl names at this level are name and field */
32359161Smckusick 	if (namelen != 2)
32459161Smckusick 		return (ENOTDIR);		/* overloaded */
32559161Smckusick 	cdp = debugvars[name[0]];
32659161Smckusick 	if (cdp->debugname == 0)
32759161Smckusick 		return (EOPNOTSUPP);
32859161Smckusick 	switch (name[1]) {
32959161Smckusick 	case CTL_DEBUG_NAME:
33059161Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
33159161Smckusick 	case CTL_DEBUG_VALUE:
33259161Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
33359161Smckusick 	default:
33459161Smckusick 		return (EOPNOTSUPP);
33559161Smckusick 	}
33659161Smckusick 	/* NOTREACHED */
33759161Smckusick }
33859161Smckusick #endif /* DEBUG */
33959161Smckusick 
34059161Smckusick /*
34157843Smckusick  * Validate parameters and get old / set new parameters
34257843Smckusick  * for an integer-valued sysctl function.
34357843Smckusick  */
34457843Smckusick sysctl_int(oldp, oldlenp, newp, newlen, valp)
34557843Smckusick 	void *oldp;
34658466Sbostic 	size_t *oldlenp;
34757843Smckusick 	void *newp;
34858466Sbostic 	size_t newlen;
34957843Smckusick 	int *valp;
35057843Smckusick {
35157843Smckusick 	int error = 0;
35257843Smckusick 
35357843Smckusick 	if (oldp && *oldlenp < sizeof(int))
35457843Smckusick 		return (ENOMEM);
35557843Smckusick 	if (newp && newlen != sizeof(int))
35657843Smckusick 		return (EINVAL);
35757843Smckusick 	*oldlenp = sizeof(int);
35857843Smckusick 	if (oldp)
35957843Smckusick 		error = copyout(valp, oldp, sizeof(int));
36057843Smckusick 	if (error == 0 && newp)
36157843Smckusick 		error = copyin(newp, valp, sizeof(int));
36243444Smckusick 	return (error);
36339963Smarc }
36439963Smarc 
36557843Smckusick /*
36657843Smckusick  * As above, but read-only.
36757843Smckusick  */
36857843Smckusick sysctl_rdint(oldp, oldlenp, newp, val)
36957843Smckusick 	void *oldp;
37058466Sbostic 	size_t *oldlenp;
37157843Smckusick 	void *newp;
37257843Smckusick 	int val;
37357843Smckusick {
37457843Smckusick 	int error = 0;
37557843Smckusick 
37657843Smckusick 	if (oldp && *oldlenp < sizeof(int))
37757843Smckusick 		return (ENOMEM);
37857843Smckusick 	if (newp)
37957843Smckusick 		return (EPERM);
38057843Smckusick 	*oldlenp = sizeof(int);
38157843Smckusick 	if (oldp)
38257843Smckusick 		error = copyout((caddr_t)&val, oldp, sizeof(int));
38357843Smckusick 	return (error);
38457843Smckusick }
38557843Smckusick 
38657843Smckusick /*
38757843Smckusick  * Validate parameters and get old / set new parameters
38857843Smckusick  * for a string-valued sysctl function.
38957843Smckusick  */
39057843Smckusick sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
39157843Smckusick 	void *oldp;
39258466Sbostic 	size_t *oldlenp;
39357843Smckusick 	void *newp;
39458466Sbostic 	size_t newlen;
39557843Smckusick 	char *str;
39657843Smckusick 	int maxlen;
39757843Smckusick {
39857843Smckusick 	int len, error = 0;
39957843Smckusick 
40057843Smckusick 	len = strlen(str) + 1;
40157843Smckusick 	if (oldp && *oldlenp < len)
40257843Smckusick 		return (ENOMEM);
40357843Smckusick 	if (newp && newlen >= maxlen)
40457843Smckusick 		return (EINVAL);
40558128Sralph 	if (oldp) {
40658128Sralph 		*oldlenp = len;
40757843Smckusick 		error = copyout(str, oldp, len);
40858128Sralph 	}
40957843Smckusick 	if (error == 0 && newp) {
41057843Smckusick 		error = copyin(newp, str, newlen);
41157843Smckusick 		str[newlen] = 0;
41257843Smckusick 	}
41357843Smckusick 	return (error);
41457843Smckusick }
41557843Smckusick 
41657843Smckusick /*
41757843Smckusick  * As above, but read-only.
41857843Smckusick  */
41957843Smckusick sysctl_rdstring(oldp, oldlenp, newp, str)
42057843Smckusick 	void *oldp;
42158466Sbostic 	size_t *oldlenp;
42257843Smckusick 	void *newp;
42357843Smckusick 	char *str;
42457843Smckusick {
42557843Smckusick 	int len, error = 0;
42657843Smckusick 
42757843Smckusick 	len = strlen(str) + 1;
42857843Smckusick 	if (oldp && *oldlenp < len)
42957843Smckusick 		return (ENOMEM);
43057843Smckusick 	if (newp)
43157843Smckusick 		return (EPERM);
43257843Smckusick 	*oldlenp = len;
43357843Smckusick 	if (oldp)
43457843Smckusick 		error = copyout(str, oldp, len);
43557843Smckusick 	return (error);
43657843Smckusick }
43757843Smckusick 
43857843Smckusick /*
43959312Smckusick  * Validate parameters and get old / set new parameters
44059312Smckusick  * for a structure oriented sysctl function.
44159312Smckusick  */
44259312Smckusick sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
44359312Smckusick 	void *oldp;
44459312Smckusick 	size_t *oldlenp;
44559312Smckusick 	void *newp;
44659312Smckusick 	size_t newlen;
44759312Smckusick 	void *sp;
44859312Smckusick 	int len;
44959312Smckusick {
45059312Smckusick 	int error = 0;
45159312Smckusick 
45259312Smckusick 	if (oldp && *oldlenp < len)
45359312Smckusick 		return (ENOMEM);
45459312Smckusick 	if (newp && newlen > len)
45559312Smckusick 		return (EINVAL);
45659312Smckusick 	if (oldp) {
45759312Smckusick 		*oldlenp = len;
45859312Smckusick 		error = copyout(sp, oldp, len);
45959312Smckusick 	}
46059312Smckusick 	if (error == 0 && newp)
46159312Smckusick 		error = copyin(newp, sp, len);
46259312Smckusick 	return (error);
46359312Smckusick }
46459312Smckusick 
46559312Smckusick /*
46657843Smckusick  * Validate parameters and get old parameters
46757843Smckusick  * for a structure oriented sysctl function.
46857843Smckusick  */
46957843Smckusick sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
47057843Smckusick 	void *oldp;
47158466Sbostic 	size_t *oldlenp;
47258466Sbostic 	void *newp, *sp;
47357843Smckusick 	int len;
47457843Smckusick {
47557843Smckusick 	int error = 0;
47657843Smckusick 
47757843Smckusick 	if (oldp && *oldlenp < len)
47857843Smckusick 		return (ENOMEM);
47957843Smckusick 	if (newp)
48057843Smckusick 		return (EPERM);
48157843Smckusick 	*oldlenp = len;
48257843Smckusick 	if (oldp)
48357843Smckusick 		error = copyout(sp, oldp, len);
48457843Smckusick 	return (error);
48557843Smckusick }
48657843Smckusick 
48757843Smckusick /*
48857843Smckusick  * Get file structures.
48957843Smckusick  */
49057843Smckusick sysctl_file(where, sizep)
49157843Smckusick 	char *where;
49258466Sbostic 	size_t *sizep;
49357843Smckusick {
49457843Smckusick 	int buflen, error;
49557843Smckusick 	struct file *fp;
49657843Smckusick 	char *start = where;
49757843Smckusick 
49857843Smckusick 	buflen = *sizep;
49957843Smckusick 	if (where == NULL) {
50057843Smckusick 		/*
50157843Smckusick 		 * overestimate by 10 files
50257843Smckusick 		 */
50357843Smckusick 		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
50457843Smckusick 		return (0);
50557843Smckusick 	}
50657843Smckusick 
50757843Smckusick 	/*
50857843Smckusick 	 * first copyout filehead
50957843Smckusick 	 */
51057843Smckusick 	if (buflen < sizeof(filehead)) {
51157843Smckusick 		*sizep = 0;
51257843Smckusick 		return (0);
51357843Smckusick 	}
51457843Smckusick 	if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
51557843Smckusick 		return (error);
51657843Smckusick 	buflen += sizeof(filehead);
51757843Smckusick 	where += sizeof(filehead);
51857843Smckusick 
51957843Smckusick 	/*
52057843Smckusick 	 * followed by an array of file structures
52157843Smckusick 	 */
52257843Smckusick 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
52357843Smckusick 		if (buflen < sizeof(struct file)) {
52457843Smckusick 			*sizep = where - start;
52557843Smckusick 			return (ENOMEM);
52657843Smckusick 		}
52757843Smckusick 		if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
52857843Smckusick 			return (error);
52957843Smckusick 		buflen -= sizeof(struct file);
53057843Smckusick 		where += sizeof(struct file);
53157843Smckusick 	}
53257843Smckusick 	*sizep = where - start;
53357843Smckusick 	return (0);
53457843Smckusick }
53557843Smckusick 
53659312Smckusick /*
53759312Smckusick  * try over estimating by 5 procs
53839963Smarc  */
53957843Smckusick #define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
54039963Smarc 
54157843Smckusick sysctl_doproc(name, namelen, where, sizep)
54257843Smckusick 	int *name;
54358466Sbostic 	u_int namelen;
54439963Smarc 	char *where;
54558466Sbostic 	size_t *sizep;
54639963Smarc {
54739963Smarc 	register struct proc *p;
54843419Smarc 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
54957843Smckusick 	register int needed = 0;
55057843Smckusick 	int buflen = where != NULL ? *sizep : 0;
55139963Smarc 	int doingzomb;
55240067Smarc 	struct eproc eproc;
55339963Smarc 	int error = 0;
55439963Smarc 
55557843Smckusick 	if (namelen != 2)
55657843Smckusick 		return (EINVAL);
55754755Storek 	p = (struct proc *)allproc;
55839963Smarc 	doingzomb = 0;
55939963Smarc again:
56039963Smarc 	for (; p != NULL; p = p->p_nxt) {
56153819Smckusick 		/*
56253819Smckusick 		 * Skip embryonic processes.
56353819Smckusick 		 */
56453819Smckusick 		if (p->p_stat == SIDL)
56553819Smckusick 			continue;
56659312Smckusick 		/*
56739963Smarc 		 * TODO - make more efficient (see notes below).
56859312Smckusick 		 * do by session.
56939963Smarc 		 */
57057843Smckusick 		switch (name[0]) {
57139963Smarc 
57257843Smckusick 		case KERN_PROC_PID:
57339963Smarc 			/* could do this with just a lookup */
57457843Smckusick 			if (p->p_pid != (pid_t)name[1])
57539963Smarc 				continue;
57639963Smarc 			break;
57739963Smarc 
57857843Smckusick 		case KERN_PROC_PGRP:
57939963Smarc 			/* could do this by traversing pgrp */
58057843Smckusick 			if (p->p_pgrp->pg_id != (pid_t)name[1])
58139963Smarc 				continue;
58239963Smarc 			break;
58339963Smarc 
58457843Smckusick 		case KERN_PROC_TTY:
58559312Smckusick 			if ((p->p_flag&SCTTY) == 0 ||
58639963Smarc 			    p->p_session->s_ttyp == NULL ||
58757843Smckusick 			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
58839963Smarc 				continue;
58939963Smarc 			break;
59039963Smarc 
59157843Smckusick 		case KERN_PROC_UID:
59257843Smckusick 			if (p->p_ucred->cr_uid != (uid_t)name[1])
59339963Smarc 				continue;
59439963Smarc 			break;
59539963Smarc 
59657843Smckusick 		case KERN_PROC_RUID:
59757843Smckusick 			if (p->p_cred->p_ruid != (uid_t)name[1])
59839963Smarc 				continue;
59939963Smarc 			break;
60039963Smarc 		}
60157843Smckusick 		if (buflen >= sizeof(struct kinfo_proc)) {
60248407Skarels 			fill_eproc(p, &eproc);
60359312Smckusick 			if (error = copyout((caddr_t)p, &dp->kp_proc,
60457843Smckusick 			    sizeof(struct proc)))
60539963Smarc 				return (error);
60659312Smckusick 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
60757843Smckusick 			    sizeof(eproc)))
60839963Smarc 				return (error);
60943419Smarc 			dp++;
61057843Smckusick 			buflen -= sizeof(struct kinfo_proc);
61139963Smarc 		}
61257843Smckusick 		needed += sizeof(struct kinfo_proc);
61339963Smarc 	}
61439963Smarc 	if (doingzomb == 0) {
61539963Smarc 		p = zombproc;
61639963Smarc 		doingzomb++;
61739963Smarc 		goto again;
61839963Smarc 	}
61957843Smckusick 	if (where != NULL) {
62057843Smckusick 		*sizep = (caddr_t)dp - where;
62157843Smckusick 		if (needed > *sizep)
62257843Smckusick 			return (ENOMEM);
62357843Smckusick 	} else {
62457843Smckusick 		needed += KERN_PROCSLOP;
62557843Smckusick 		*sizep = needed;
62657843Smckusick 	}
62739963Smarc 	return (0);
62839963Smarc }
62948407Skarels 
63048407Skarels /*
63148407Skarels  * Fill in an eproc structure for the specified process.
63248407Skarels  */
63348407Skarels void
63448407Skarels fill_eproc(p, ep)
63548407Skarels 	register struct proc *p;
63648407Skarels 	register struct eproc *ep;
63748407Skarels {
63848407Skarels 	register struct tty *tp;
63948407Skarels 
64048407Skarels 	ep->e_paddr = p;
64148407Skarels 	ep->e_sess = p->p_pgrp->pg_session;
64248407Skarels 	ep->e_pcred = *p->p_cred;
64348407Skarels 	ep->e_ucred = *p->p_ucred;
64452405Storek 	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
64552405Storek 		ep->e_vm.vm_rssize = 0;
64652405Storek 		ep->e_vm.vm_tsize = 0;
64752405Storek 		ep->e_vm.vm_dsize = 0;
64852405Storek 		ep->e_vm.vm_ssize = 0;
64952405Storek #ifndef sparc
65052405Storek 		/* ep->e_vm.vm_pmap = XXX; */
65152405Storek #endif
65252405Storek 	} else {
65352405Storek 		register struct vmspace *vm = p->p_vmspace;
65452405Storek 
65552405Storek 		ep->e_vm.vm_rssize = vm->vm_rssize;
65652405Storek 		ep->e_vm.vm_tsize = vm->vm_tsize;
65752405Storek 		ep->e_vm.vm_dsize = vm->vm_dsize;
65852405Storek 		ep->e_vm.vm_ssize = vm->vm_ssize;
65952405Storek #ifndef sparc
66052405Storek 		ep->e_vm.vm_pmap = vm->vm_pmap;
66152405Storek #endif
66252405Storek 	}
66349141Skarels 	if (p->p_pptr)
66449141Skarels 		ep->e_ppid = p->p_pptr->p_pid;
66549141Skarels 	else
66649141Skarels 		ep->e_ppid = 0;
66748407Skarels 	ep->e_pgid = p->p_pgrp->pg_id;
66848407Skarels 	ep->e_jobc = p->p_pgrp->pg_jobc;
66959312Smckusick 	if ((p->p_flag&SCTTY) &&
67048407Skarels 	     (tp = ep->e_sess->s_ttyp)) {
67148407Skarels 		ep->e_tdev = tp->t_dev;
67250022Skarels 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
67348407Skarels 		ep->e_tsess = tp->t_session;
67448407Skarels 	} else
67548407Skarels 		ep->e_tdev = NODEV;
67648407Skarels 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
67748407Skarels 	if (SESS_LEADER(p))
67848407Skarels 		ep->e_flag |= EPROC_SLEADER;
67948407Skarels 	if (p->p_wmesg)
68048407Skarels 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
68148407Skarels 	ep->e_xsize = ep->e_xrssize = 0;
68248407Skarels 	ep->e_xccount = ep->e_xswrss = 0;
68348407Skarels }
68450149Smarc 
68557843Smckusick #ifdef COMPAT_43
68657843Smckusick #include <sys/socket.h>
68757906Smckusick #define	KINFO_PROC		(0<<8)
68857906Smckusick #define	KINFO_RT		(1<<8)
68957906Smckusick #define	KINFO_VNODE		(2<<8)
69057906Smckusick #define	KINFO_FILE		(3<<8)
69157906Smckusick #define	KINFO_METER		(4<<8)
69257906Smckusick #define	KINFO_LOADAVG		(5<<8)
69357906Smckusick #define	KINFO_CLOCKRATE		(6<<8)
69457843Smckusick 
69557843Smckusick struct getkerninfo_args {
69657843Smckusick 	int	op;
69757843Smckusick 	char	*where;
69857843Smckusick 	int	*size;
69957843Smckusick 	int	arg;
70057843Smckusick };
70157843Smckusick 
70258943Smckusick ogetkerninfo(p, uap, retval)
70357843Smckusick 	struct proc *p;
70457843Smckusick 	register struct getkerninfo_args *uap;
70557843Smckusick 	int *retval;
70650149Smarc {
70757843Smckusick 	int error, name[5];
70857843Smckusick 	u_int size;
70950149Smarc 
71058461Smckusick 	if (uap->size &&
71158466Sbostic 	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
71257843Smckusick 		return (error);
71350149Smarc 
71457906Smckusick 	switch (uap->op & 0xff00) {
71550149Smarc 
71657843Smckusick 	case KINFO_RT:
71757843Smckusick 		name[0] = PF_ROUTE;
71857843Smckusick 		name[1] = 0;
71957843Smckusick 		name[2] = (uap->op & 0xff0000) >> 16;
72057843Smckusick 		name[3] = uap->op & 0xff;
72157843Smckusick 		name[4] = uap->arg;
72258415Smckusick 		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
72357843Smckusick 		break;
72457843Smckusick 
72557843Smckusick 	case KINFO_VNODE:
72657843Smckusick 		name[0] = KERN_VNODE;
72758415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
72857843Smckusick 		break;
72957843Smckusick 
73057843Smckusick 	case KINFO_PROC:
73157843Smckusick 		name[0] = KERN_PROC;
73257843Smckusick 		name[1] = uap->op & 0xff;
73357843Smckusick 		name[2] = uap->arg;
73458415Smckusick 		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
73557843Smckusick 		break;
73657843Smckusick 
73757843Smckusick 	case KINFO_FILE:
73857843Smckusick 		name[0] = KERN_FILE;
73958415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
74057843Smckusick 		break;
74157843Smckusick 
74257843Smckusick 	case KINFO_METER:
74357843Smckusick 		name[0] = VM_METER;
74458415Smckusick 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
74557843Smckusick 		break;
74657843Smckusick 
74757843Smckusick 	case KINFO_LOADAVG:
74857843Smckusick 		name[0] = VM_LOADAVG;
74958415Smckusick 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
75057843Smckusick 		break;
75157843Smckusick 
75257843Smckusick 	case KINFO_CLOCKRATE:
75357843Smckusick 		name[0] = KERN_CLOCKRATE;
75458415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
75557843Smckusick 		break;
75657843Smckusick 
75757843Smckusick 	default:
75858415Smckusick 		return (EOPNOTSUPP);
75950149Smarc 	}
76057843Smckusick 	if (error)
76157843Smckusick 		return (error);
76257843Smckusick 	*retval = size;
76358461Smckusick 	if (uap->size)
76458461Smckusick 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
76558461Smckusick 		    sizeof(size));
76658461Smckusick 	return (error);
76750149Smarc }
76857843Smckusick #endif /* COMPAT_43 */
769