xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 59161)
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*59161Smckusick  *	@(#)kern_sysctl.c	7.33 (Berkeley) 04/19/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>
2257843Smckusick #include <sys/sysctl.h>
2357843Smckusick #include <sys/unistd.h>
2457843Smckusick #include <sys/buf.h>
2556517Sbostic #include <sys/ioctl.h>
2656517Sbostic #include <sys/tty.h>
2739963Smarc 
2856517Sbostic #include <vm/vm.h>
2948407Skarels 
3056517Sbostic #include <sys/kinfo_proc.h>
3148407Skarels 
3257843Smckusick sysctlfn kern_sysctl;
3357843Smckusick sysctlfn hw_sysctl;
34*59161Smckusick #ifdef DEBUG
35*59161Smckusick sysctlfn debug_sysctl;
36*59161Smckusick #endif
3757843Smckusick extern sysctlfn vm_sysctl;
3857843Smckusick extern sysctlfn fs_sysctl;
3957843Smckusick extern sysctlfn net_sysctl;
4057843Smckusick extern sysctlfn cpu_sysctl;
4140068Smarc 
4257843Smckusick /*
4357843Smckusick  * Locking and stats
4457843Smckusick  */
4557843Smckusick static struct sysctl_lock {
4657843Smckusick 	int	sl_lock;
4757843Smckusick 	int	sl_want;
4857843Smckusick 	int	sl_locked;
4957843Smckusick } memlock;
5057843Smckusick 
5157843Smckusick struct sysctl_args {
5257843Smckusick 	int	*name;
5357843Smckusick 	u_int	namelen;
5457843Smckusick 	void	*old;
5558466Sbostic 	size_t	*oldlenp;
5657843Smckusick 	void	*new;
5758466Sbostic 	size_t	newlen;
5854923Storek };
5957843Smckusick 
6057843Smckusick sysctl(p, uap, retval)
6143444Smckusick 	struct proc *p;
6257843Smckusick 	register struct sysctl_args *uap;
6343444Smckusick 	int *retval;
6443444Smckusick {
6557843Smckusick 	int error, dolock = 1;
6657843Smckusick 	u_int savelen, oldlen = 0;
6757843Smckusick 	sysctlfn *fn;
6857843Smckusick 	int name[CTL_MAXNAME];
6939963Smarc 
7057843Smckusick 	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
7157843Smckusick 		return (error);
7257843Smckusick 	/*
7357843Smckusick 	 * all top-level sysctl names are non-terminal
7457843Smckusick 	 */
7557843Smckusick 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
7657843Smckusick 		return (EINVAL);
7757843Smckusick 	if (error = copyin(uap->name, &name, uap->namelen * sizeof(int)))
7857843Smckusick 		return (error);
7939963Smarc 
8057843Smckusick 	switch (name[0]) {
8157843Smckusick 	case CTL_KERN:
8257843Smckusick 		fn = kern_sysctl;
8357843Smckusick 		if (name[2] != KERN_VNODE)	/* XXX */
8457843Smckusick 			dolock = 0;
8539963Smarc 		break;
8657843Smckusick 	case CTL_HW:
8757843Smckusick 		fn = hw_sysctl;
8840068Smarc 		break;
8957843Smckusick 	case CTL_VM:
9057843Smckusick 		fn = vm_sysctl;
9141181Smarc 		break;
9257843Smckusick 	case CTL_NET:
9357843Smckusick 		fn = net_sysctl;
9450149Smarc 		break;
9557843Smckusick #ifdef notyet
9657843Smckusick 	case CTL_FS:
9757843Smckusick 		fn = fs_sysctl;
9850909Smckusick 		break;
9957843Smckusick 	case CTL_MACHDEP:
10057843Smckusick 		fn = cpu_sysctl;
10152669Smckusick 		break;
10257843Smckusick #endif
103*59161Smckusick #ifdef DEBUG
104*59161Smckusick 	case CTL_DEBUG:
105*59161Smckusick 		fn = debug_sysctl;
106*59161Smckusick 		break;
107*59161Smckusick #endif
10839963Smarc 	default:
10957843Smckusick 		return (EOPNOTSUPP);
11039963Smarc 	}
11157843Smckusick 
11257843Smckusick 	if (uap->oldlenp &&
11357843Smckusick 	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
11457843Smckusick 		return (error);
11557843Smckusick 	if (uap->old != NULL) {
11657843Smckusick 		if (!useracc(uap->old, oldlen, B_WRITE))
11757843Smckusick 			return (EFAULT);
11857843Smckusick 		while (memlock.sl_lock) {
11957843Smckusick 			memlock.sl_want = 1;
12057843Smckusick 			sleep((caddr_t)&memlock, PRIBIO+1);
12157843Smckusick 			memlock.sl_locked++;
12257843Smckusick 		}
12357843Smckusick 		memlock.sl_lock = 1;
12457843Smckusick 		if (dolock)
12557843Smckusick 			vslock(uap->old, oldlen);
12657843Smckusick 		savelen = oldlen;
12740813Smarc 	}
12857843Smckusick 	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
12958415Smckusick 	    uap->new, uap->newlen, p);
13057843Smckusick 	if (uap->old != NULL) {
13157843Smckusick 		if (dolock)
13257843Smckusick 			vsunlock(uap->old, savelen, B_WRITE);
13357843Smckusick 		memlock.sl_lock = 0;
13457843Smckusick 		if (memlock.sl_want) {
13557843Smckusick 			memlock.sl_want = 0;
13657843Smckusick 			wakeup((caddr_t)&memlock);
13757843Smckusick 		}
13840206Smarc 	}
13957843Smckusick 	if (error)
14057843Smckusick 		return (error);
14157843Smckusick 	if (uap->oldlenp)
14257843Smckusick 		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
14357843Smckusick 	*retval = oldlen;
14457843Smckusick 	return (0);
14557843Smckusick }
14640206Smarc 
14757843Smckusick /*
14857843Smckusick  * Attributes stored in the kernel.
14957843Smckusick  */
15057843Smckusick char hostname[MAXHOSTNAMELEN];
15157843Smckusick int hostnamelen;
15257843Smckusick long hostid;
15358415Smckusick int securelevel;
15457843Smckusick 
15558415Smckusick /*
15658415Smckusick  * kernel related system variables.
15758415Smckusick  */
15858415Smckusick kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
15957843Smckusick 	int *name;
16057843Smckusick 	u_int namelen;
16157843Smckusick 	void *oldp;
16258466Sbostic 	size_t *oldlenp;
16357843Smckusick 	void *newp;
16458466Sbostic 	size_t newlen;
16558415Smckusick 	struct proc *p;
16657843Smckusick {
16758415Smckusick 	int error, level;
16857843Smckusick 	extern char ostype[], osrelease[], version[];
16957843Smckusick 
17057843Smckusick 	/* all sysctl names at this level are terminal */
17157843Smckusick 	if (namelen != 1 && name[0] != KERN_PROC)
17257843Smckusick 		return (ENOTDIR);		/* overloaded */
17357843Smckusick 
17457843Smckusick 	switch (name[0]) {
17557843Smckusick 	case KERN_OSTYPE:
17657843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
17757843Smckusick 	case KERN_OSRELEASE:
17857843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
17957843Smckusick 	case KERN_OSREV:
18057843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
18157843Smckusick 	case KERN_VERSION:
18257843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, version));
18357843Smckusick 	case KERN_POSIX1:
18457843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
18557843Smckusick 	case KERN_MAXPROC:
18657843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
18757843Smckusick 	case KERN_MAXFILES:
18857843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
18957843Smckusick 	case KERN_ARGMAX:
19057843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
19157843Smckusick 	case KERN_HOSTNAME:
19257843Smckusick 		error = sysctl_string(oldp, oldlenp, newp, newlen,
19357843Smckusick 		    hostname, sizeof(hostname));
19457843Smckusick 		if (!error)
19557843Smckusick 			hostnamelen = newlen;
19657843Smckusick 		return (error);
19757843Smckusick 	case KERN_HOSTID:
19857843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &hostid));
19958415Smckusick 	case KERN_SECURELVL:
20058415Smckusick 		level = securelevel;
20158415Smckusick 		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
20258415Smckusick 		    newp == NULL)
20358415Smckusick 			return (error);
20458415Smckusick 		if (level < securelevel && p->p_pid != 1)
20558415Smckusick 			return (EPERM);
20658415Smckusick 		securelevel = level;
20758415Smckusick 		return (0);
20857843Smckusick 	case KERN_CLOCKRATE:
20957843Smckusick 		return (sysctl_clockrate(oldp, oldlenp));
21057843Smckusick 	case KERN_FILE:
21157843Smckusick 		return (sysctl_file(oldp, oldlenp));
21257843Smckusick 	case KERN_VNODE:
21357843Smckusick 		return (sysctl_vnode(oldp, oldlenp));
21457843Smckusick 	case KERN_PROC:
21557843Smckusick 		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
21657843Smckusick 	default:
21757843Smckusick 		return (EOPNOTSUPP);
21852405Storek 	}
21957843Smckusick 	/* NOTREACHED */
22057843Smckusick }
22157843Smckusick 
22258415Smckusick /*
22358415Smckusick  * hardware related system variables.
22458415Smckusick  */
22558415Smckusick hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
22657843Smckusick 	int *name;
22757843Smckusick 	u_int namelen;
22857843Smckusick 	void *oldp;
22958466Sbostic 	size_t *oldlenp;
23057843Smckusick 	void *newp;
23158466Sbostic 	size_t newlen;
23258415Smckusick 	struct proc *p;
23357843Smckusick {
23457843Smckusick 	extern char machine[], cpu_model[];
23557843Smckusick 
23657843Smckusick 	/* all sysctl names at this level are terminal */
23757843Smckusick 	if (namelen != 1)
23857843Smckusick 		return (ENOTDIR);		/* overloaded */
23957843Smckusick 
24057843Smckusick 	switch (name[0]) {
24157843Smckusick 	case HW_MACHINE:
24257843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
24357843Smckusick 	case HW_MODEL:
24457843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
24557843Smckusick 	case HW_NCPU:
24657843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
24757843Smckusick 	case HW_CPUSPEED:
24857843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, cpuspeed));
24957843Smckusick 	case HW_PHYSMEM:
25057843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
25157843Smckusick 	case HW_USERMEM:
25257843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp,
25357843Smckusick 		    ctob(physmem - cnt.v_wire_count)));
25457843Smckusick 	case HW_PAGESIZE:
25557843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
25657843Smckusick 	default:
25757843Smckusick 		return (EOPNOTSUPP);
25857843Smckusick 	}
25957843Smckusick 	/* NOTREACHED */
26057843Smckusick }
26157843Smckusick 
262*59161Smckusick #ifdef DEBUG
26357843Smckusick /*
264*59161Smckusick  * Debugging related system variables.
265*59161Smckusick  */
266*59161Smckusick struct ctldebug debug0, debug1, debug2, debug3, debug4;
267*59161Smckusick struct ctldebug debug5, debug6, debug7, debug8, debug9;
268*59161Smckusick struct ctldebug debug10, debug11, debug12, debug13, debug14;
269*59161Smckusick struct ctldebug debug15, debug16, debug17, debug18, debug19;
270*59161Smckusick static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
271*59161Smckusick 	&debug0, &debug1, &debug2, &debug3, &debug4,
272*59161Smckusick 	&debug5, &debug6, &debug7, &debug8, &debug9,
273*59161Smckusick 	&debug10, &debug11, &debug12, &debug13, &debug14,
274*59161Smckusick 	&debug15, &debug16, &debug17, &debug18, &debug19,
275*59161Smckusick };
276*59161Smckusick int
277*59161Smckusick debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
278*59161Smckusick 	int *name;
279*59161Smckusick 	u_int namelen;
280*59161Smckusick 	void *oldp;
281*59161Smckusick 	size_t *oldlenp;
282*59161Smckusick 	void *newp;
283*59161Smckusick 	size_t newlen;
284*59161Smckusick 	struct proc *p;
285*59161Smckusick {
286*59161Smckusick 	struct ctldebug *cdp;
287*59161Smckusick 
288*59161Smckusick 	/* all sysctl names at this level are name and field */
289*59161Smckusick 	if (namelen != 2)
290*59161Smckusick 		return (ENOTDIR);		/* overloaded */
291*59161Smckusick 	cdp = debugvars[name[0]];
292*59161Smckusick 	if (cdp->debugname == 0)
293*59161Smckusick 		return (EOPNOTSUPP);
294*59161Smckusick 	switch (name[1]) {
295*59161Smckusick 	case CTL_DEBUG_NAME:
296*59161Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
297*59161Smckusick 	case CTL_DEBUG_VALUE:
298*59161Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
299*59161Smckusick 	default:
300*59161Smckusick 		return (EOPNOTSUPP);
301*59161Smckusick 	}
302*59161Smckusick 	/* NOTREACHED */
303*59161Smckusick }
304*59161Smckusick #endif /* DEBUG */
305*59161Smckusick 
306*59161Smckusick /*
30757843Smckusick  * Validate parameters and get old / set new parameters
30857843Smckusick  * for an integer-valued sysctl function.
30957843Smckusick  */
31057843Smckusick sysctl_int(oldp, oldlenp, newp, newlen, valp)
31157843Smckusick 	void *oldp;
31258466Sbostic 	size_t *oldlenp;
31357843Smckusick 	void *newp;
31458466Sbostic 	size_t newlen;
31557843Smckusick 	int *valp;
31657843Smckusick {
31757843Smckusick 	int error = 0;
31857843Smckusick 
31957843Smckusick 	if (oldp && *oldlenp < sizeof(int))
32057843Smckusick 		return (ENOMEM);
32157843Smckusick 	if (newp && newlen != sizeof(int))
32257843Smckusick 		return (EINVAL);
32357843Smckusick 	*oldlenp = sizeof(int);
32457843Smckusick 	if (oldp)
32557843Smckusick 		error = copyout(valp, oldp, sizeof(int));
32657843Smckusick 	if (error == 0 && newp)
32757843Smckusick 		error = copyin(newp, valp, sizeof(int));
32843444Smckusick 	return (error);
32939963Smarc }
33039963Smarc 
33157843Smckusick /*
33257843Smckusick  * As above, but read-only.
33357843Smckusick  */
33457843Smckusick sysctl_rdint(oldp, oldlenp, newp, val)
33557843Smckusick 	void *oldp;
33658466Sbostic 	size_t *oldlenp;
33757843Smckusick 	void *newp;
33857843Smckusick 	int val;
33957843Smckusick {
34057843Smckusick 	int error = 0;
34157843Smckusick 
34257843Smckusick 	if (oldp && *oldlenp < sizeof(int))
34357843Smckusick 		return (ENOMEM);
34457843Smckusick 	if (newp)
34557843Smckusick 		return (EPERM);
34657843Smckusick 	*oldlenp = sizeof(int);
34757843Smckusick 	if (oldp)
34857843Smckusick 		error = copyout((caddr_t)&val, oldp, sizeof(int));
34957843Smckusick 	return (error);
35057843Smckusick }
35157843Smckusick 
35257843Smckusick /*
35357843Smckusick  * Validate parameters and get old / set new parameters
35457843Smckusick  * for a string-valued sysctl function.
35557843Smckusick  */
35657843Smckusick sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
35757843Smckusick 	void *oldp;
35858466Sbostic 	size_t *oldlenp;
35957843Smckusick 	void *newp;
36058466Sbostic 	size_t newlen;
36157843Smckusick 	char *str;
36257843Smckusick 	int maxlen;
36357843Smckusick {
36457843Smckusick 	int len, error = 0;
36557843Smckusick 
36657843Smckusick 	len = strlen(str) + 1;
36757843Smckusick 	if (oldp && *oldlenp < len)
36857843Smckusick 		return (ENOMEM);
36957843Smckusick 	if (newp && newlen >= maxlen)
37057843Smckusick 		return (EINVAL);
37158128Sralph 	if (oldp) {
37258128Sralph 		*oldlenp = len;
37357843Smckusick 		error = copyout(str, oldp, len);
37458128Sralph 	}
37557843Smckusick 	if (error == 0 && newp) {
37657843Smckusick 		error = copyin(newp, str, newlen);
37757843Smckusick 		str[newlen] = 0;
37857843Smckusick 	}
37957843Smckusick 	return (error);
38057843Smckusick }
38157843Smckusick 
38257843Smckusick /*
38357843Smckusick  * As above, but read-only.
38457843Smckusick  */
38557843Smckusick sysctl_rdstring(oldp, oldlenp, newp, str)
38657843Smckusick 	void *oldp;
38758466Sbostic 	size_t *oldlenp;
38857843Smckusick 	void *newp;
38957843Smckusick 	char *str;
39057843Smckusick {
39157843Smckusick 	int len, error = 0;
39257843Smckusick 
39357843Smckusick 	len = strlen(str) + 1;
39457843Smckusick 	if (oldp && *oldlenp < len)
39557843Smckusick 		return (ENOMEM);
39657843Smckusick 	if (newp)
39757843Smckusick 		return (EPERM);
39857843Smckusick 	*oldlenp = len;
39957843Smckusick 	if (oldp)
40057843Smckusick 		error = copyout(str, oldp, len);
40157843Smckusick 	return (error);
40257843Smckusick }
40357843Smckusick 
40457843Smckusick /*
40557843Smckusick  * Validate parameters and get old parameters
40657843Smckusick  * for a structure oriented sysctl function.
40757843Smckusick  */
40857843Smckusick sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
40957843Smckusick 	void *oldp;
41058466Sbostic 	size_t *oldlenp;
41158466Sbostic 	void *newp, *sp;
41257843Smckusick 	int len;
41357843Smckusick {
41457843Smckusick 	int error = 0;
41557843Smckusick 
41657843Smckusick 	if (oldp && *oldlenp < len)
41757843Smckusick 		return (ENOMEM);
41857843Smckusick 	if (newp)
41957843Smckusick 		return (EPERM);
42057843Smckusick 	*oldlenp = len;
42157843Smckusick 	if (oldp)
42257843Smckusick 		error = copyout(sp, oldp, len);
42357843Smckusick 	return (error);
42457843Smckusick }
42557843Smckusick 
42657843Smckusick /*
42757843Smckusick  * Get file structures.
42857843Smckusick  */
42957843Smckusick sysctl_file(where, sizep)
43057843Smckusick 	char *where;
43158466Sbostic 	size_t *sizep;
43257843Smckusick {
43357843Smckusick 	int buflen, error;
43457843Smckusick 	struct file *fp;
43557843Smckusick 	char *start = where;
43657843Smckusick 
43757843Smckusick 	buflen = *sizep;
43857843Smckusick 	if (where == NULL) {
43957843Smckusick 		/*
44057843Smckusick 		 * overestimate by 10 files
44157843Smckusick 		 */
44257843Smckusick 		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
44357843Smckusick 		return (0);
44457843Smckusick 	}
44557843Smckusick 
44657843Smckusick 	/*
44757843Smckusick 	 * first copyout filehead
44857843Smckusick 	 */
44957843Smckusick 	if (buflen < sizeof(filehead)) {
45057843Smckusick 		*sizep = 0;
45157843Smckusick 		return (0);
45257843Smckusick 	}
45357843Smckusick 	if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
45457843Smckusick 		return (error);
45557843Smckusick 	buflen += sizeof(filehead);
45657843Smckusick 	where += sizeof(filehead);
45757843Smckusick 
45857843Smckusick 	/*
45957843Smckusick 	 * followed by an array of file structures
46057843Smckusick 	 */
46157843Smckusick 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
46257843Smckusick 		if (buflen < sizeof(struct file)) {
46357843Smckusick 			*sizep = where - start;
46457843Smckusick 			return (ENOMEM);
46557843Smckusick 		}
46657843Smckusick 		if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
46757843Smckusick 			return (error);
46857843Smckusick 		buflen -= sizeof(struct file);
46957843Smckusick 		where += sizeof(struct file);
47057843Smckusick 	}
47157843Smckusick 	*sizep = where - start;
47257843Smckusick 	return (0);
47357843Smckusick }
47457843Smckusick 
47539963Smarc /*
47639963Smarc  * try over estimating by 5 procs
47739963Smarc  */
47857843Smckusick #define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
47939963Smarc 
48057843Smckusick sysctl_doproc(name, namelen, where, sizep)
48157843Smckusick 	int *name;
48258466Sbostic 	u_int namelen;
48339963Smarc 	char *where;
48458466Sbostic 	size_t *sizep;
48539963Smarc {
48639963Smarc 	register struct proc *p;
48743419Smarc 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
48857843Smckusick 	register int needed = 0;
48957843Smckusick 	int buflen = where != NULL ? *sizep : 0;
49039963Smarc 	int doingzomb;
49140067Smarc 	struct eproc eproc;
49239963Smarc 	int error = 0;
49339963Smarc 
49457843Smckusick 	if (namelen != 2)
49557843Smckusick 		return (EINVAL);
49654755Storek 	p = (struct proc *)allproc;
49739963Smarc 	doingzomb = 0;
49839963Smarc again:
49939963Smarc 	for (; p != NULL; p = p->p_nxt) {
50053819Smckusick 		/*
50153819Smckusick 		 * Skip embryonic processes.
50253819Smckusick 		 */
50353819Smckusick 		if (p->p_stat == SIDL)
50453819Smckusick 			continue;
50539963Smarc 		/*
50639963Smarc 		 * TODO - make more efficient (see notes below).
50739963Smarc 		 * do by session.
50839963Smarc 		 */
50957843Smckusick 		switch (name[0]) {
51039963Smarc 
51157843Smckusick 		case KERN_PROC_PID:
51239963Smarc 			/* could do this with just a lookup */
51357843Smckusick 			if (p->p_pid != (pid_t)name[1])
51439963Smarc 				continue;
51539963Smarc 			break;
51639963Smarc 
51757843Smckusick 		case KERN_PROC_PGRP:
51839963Smarc 			/* could do this by traversing pgrp */
51957843Smckusick 			if (p->p_pgrp->pg_id != (pid_t)name[1])
52039963Smarc 				continue;
52139963Smarc 			break;
52239963Smarc 
52357843Smckusick 		case KERN_PROC_TTY:
52439963Smarc 			if ((p->p_flag&SCTTY) == 0 ||
52539963Smarc 			    p->p_session->s_ttyp == NULL ||
52657843Smckusick 			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
52739963Smarc 				continue;
52839963Smarc 			break;
52939963Smarc 
53057843Smckusick 		case KERN_PROC_UID:
53157843Smckusick 			if (p->p_ucred->cr_uid != (uid_t)name[1])
53239963Smarc 				continue;
53339963Smarc 			break;
53439963Smarc 
53557843Smckusick 		case KERN_PROC_RUID:
53657843Smckusick 			if (p->p_cred->p_ruid != (uid_t)name[1])
53739963Smarc 				continue;
53839963Smarc 			break;
53939963Smarc 		}
54057843Smckusick 		if (buflen >= sizeof(struct kinfo_proc)) {
54148407Skarels 			fill_eproc(p, &eproc);
54243419Smarc 			if (error = copyout((caddr_t)p, &dp->kp_proc,
54357843Smckusick 			    sizeof(struct proc)))
54439963Smarc 				return (error);
54543419Smarc 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
54657843Smckusick 			    sizeof(eproc)))
54739963Smarc 				return (error);
54843419Smarc 			dp++;
54957843Smckusick 			buflen -= sizeof(struct kinfo_proc);
55039963Smarc 		}
55157843Smckusick 		needed += sizeof(struct kinfo_proc);
55239963Smarc 	}
55339963Smarc 	if (doingzomb == 0) {
55439963Smarc 		p = zombproc;
55539963Smarc 		doingzomb++;
55639963Smarc 		goto again;
55739963Smarc 	}
55857843Smckusick 	if (where != NULL) {
55957843Smckusick 		*sizep = (caddr_t)dp - where;
56057843Smckusick 		if (needed > *sizep)
56157843Smckusick 			return (ENOMEM);
56257843Smckusick 	} else {
56357843Smckusick 		needed += KERN_PROCSLOP;
56457843Smckusick 		*sizep = needed;
56557843Smckusick 	}
56639963Smarc 	return (0);
56739963Smarc }
56848407Skarels 
56948407Skarels /*
57048407Skarels  * Fill in an eproc structure for the specified process.
57148407Skarels  */
57248407Skarels void
57348407Skarels fill_eproc(p, ep)
57448407Skarels 	register struct proc *p;
57548407Skarels 	register struct eproc *ep;
57648407Skarels {
57748407Skarels 	register struct tty *tp;
57848407Skarels 
57948407Skarels 	ep->e_paddr = p;
58048407Skarels 	ep->e_sess = p->p_pgrp->pg_session;
58148407Skarels 	ep->e_pcred = *p->p_cred;
58248407Skarels 	ep->e_ucred = *p->p_ucred;
58352405Storek 	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
58452405Storek 		ep->e_vm.vm_rssize = 0;
58552405Storek 		ep->e_vm.vm_tsize = 0;
58652405Storek 		ep->e_vm.vm_dsize = 0;
58752405Storek 		ep->e_vm.vm_ssize = 0;
58852405Storek #ifndef sparc
58952405Storek 		/* ep->e_vm.vm_pmap = XXX; */
59052405Storek #endif
59152405Storek 	} else {
59252405Storek 		register struct vmspace *vm = p->p_vmspace;
59352405Storek 
59452405Storek 		ep->e_vm.vm_rssize = vm->vm_rssize;
59552405Storek 		ep->e_vm.vm_tsize = vm->vm_tsize;
59652405Storek 		ep->e_vm.vm_dsize = vm->vm_dsize;
59752405Storek 		ep->e_vm.vm_ssize = vm->vm_ssize;
59852405Storek #ifndef sparc
59952405Storek 		ep->e_vm.vm_pmap = vm->vm_pmap;
60052405Storek #endif
60152405Storek 	}
60249141Skarels 	if (p->p_pptr)
60349141Skarels 		ep->e_ppid = p->p_pptr->p_pid;
60449141Skarels 	else
60549141Skarels 		ep->e_ppid = 0;
60648407Skarels 	ep->e_pgid = p->p_pgrp->pg_id;
60748407Skarels 	ep->e_jobc = p->p_pgrp->pg_jobc;
60848407Skarels 	if ((p->p_flag&SCTTY) &&
60948407Skarels 	     (tp = ep->e_sess->s_ttyp)) {
61048407Skarels 		ep->e_tdev = tp->t_dev;
61150022Skarels 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
61248407Skarels 		ep->e_tsess = tp->t_session;
61348407Skarels 	} else
61448407Skarels 		ep->e_tdev = NODEV;
61548407Skarels 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
61648407Skarels 	if (SESS_LEADER(p))
61748407Skarels 		ep->e_flag |= EPROC_SLEADER;
61848407Skarels 	if (p->p_wmesg)
61948407Skarels 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
62048407Skarels 	ep->e_xsize = ep->e_xrssize = 0;
62148407Skarels 	ep->e_xccount = ep->e_xswrss = 0;
62248407Skarels }
62350149Smarc 
62457843Smckusick #ifdef COMPAT_43
62557843Smckusick #include <sys/socket.h>
62657906Smckusick #define	KINFO_PROC		(0<<8)
62757906Smckusick #define	KINFO_RT		(1<<8)
62857906Smckusick #define	KINFO_VNODE		(2<<8)
62957906Smckusick #define	KINFO_FILE		(3<<8)
63057906Smckusick #define	KINFO_METER		(4<<8)
63157906Smckusick #define	KINFO_LOADAVG		(5<<8)
63257906Smckusick #define	KINFO_CLOCKRATE		(6<<8)
63357843Smckusick 
63457843Smckusick struct getkerninfo_args {
63557843Smckusick 	int	op;
63657843Smckusick 	char	*where;
63757843Smckusick 	int	*size;
63857843Smckusick 	int	arg;
63957843Smckusick };
64057843Smckusick 
64158943Smckusick ogetkerninfo(p, uap, retval)
64257843Smckusick 	struct proc *p;
64357843Smckusick 	register struct getkerninfo_args *uap;
64457843Smckusick 	int *retval;
64550149Smarc {
64657843Smckusick 	int error, name[5];
64757843Smckusick 	u_int size;
64850149Smarc 
64958461Smckusick 	if (uap->size &&
65058466Sbostic 	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
65157843Smckusick 		return (error);
65250149Smarc 
65357906Smckusick 	switch (uap->op & 0xff00) {
65450149Smarc 
65557843Smckusick 	case KINFO_RT:
65657843Smckusick 		name[0] = PF_ROUTE;
65757843Smckusick 		name[1] = 0;
65857843Smckusick 		name[2] = (uap->op & 0xff0000) >> 16;
65957843Smckusick 		name[3] = uap->op & 0xff;
66057843Smckusick 		name[4] = uap->arg;
66158415Smckusick 		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
66257843Smckusick 		break;
66357843Smckusick 
66457843Smckusick 	case KINFO_VNODE:
66557843Smckusick 		name[0] = KERN_VNODE;
66658415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
66757843Smckusick 		break;
66857843Smckusick 
66957843Smckusick 	case KINFO_PROC:
67057843Smckusick 		name[0] = KERN_PROC;
67157843Smckusick 		name[1] = uap->op & 0xff;
67257843Smckusick 		name[2] = uap->arg;
67358415Smckusick 		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
67457843Smckusick 		break;
67557843Smckusick 
67657843Smckusick 	case KINFO_FILE:
67757843Smckusick 		name[0] = KERN_FILE;
67858415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
67957843Smckusick 		break;
68057843Smckusick 
68157843Smckusick 	case KINFO_METER:
68257843Smckusick 		name[0] = VM_METER;
68358415Smckusick 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
68457843Smckusick 		break;
68557843Smckusick 
68657843Smckusick 	case KINFO_LOADAVG:
68757843Smckusick 		name[0] = VM_LOADAVG;
68858415Smckusick 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
68957843Smckusick 		break;
69057843Smckusick 
69157843Smckusick 	case KINFO_CLOCKRATE:
69257843Smckusick 		name[0] = KERN_CLOCKRATE;
69358415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
69457843Smckusick 		break;
69557843Smckusick 
69657843Smckusick 	default:
69758415Smckusick 		return (EOPNOTSUPP);
69850149Smarc 	}
69957843Smckusick 	if (error)
70057843Smckusick 		return (error);
70157843Smckusick 	*retval = size;
70258461Smckusick 	if (uap->size)
70358461Smckusick 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
70458461Smckusick 		    sizeof(size));
70558461Smckusick 	return (error);
70650149Smarc }
70757843Smckusick #endif /* COMPAT_43 */
708