xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 59314)
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*59314Smckusick  *	@(#)kern_sysctl.c	7.35 (Berkeley) 04/27/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>
22*59314Smckusick #include <sys/vnode.h>
2357843Smckusick #include <sys/sysctl.h>
2457843Smckusick #include <sys/unistd.h>
2557843Smckusick #include <sys/buf.h>
2656517Sbostic #include <sys/ioctl.h>
2756517Sbostic #include <sys/tty.h>
2839963Smarc 
2956517Sbostic #include <vm/vm.h>
3048407Skarels 
3156517Sbostic #include <sys/kinfo_proc.h>
3248407Skarels 
3357843Smckusick sysctlfn kern_sysctl;
3457843Smckusick sysctlfn hw_sysctl;
3559161Smckusick #ifdef DEBUG
3659161Smckusick sysctlfn debug_sysctl;
3759161Smckusick #endif
3857843Smckusick extern sysctlfn vm_sysctl;
3957843Smckusick extern sysctlfn fs_sysctl;
4057843Smckusick extern sysctlfn net_sysctl;
4157843Smckusick extern sysctlfn cpu_sysctl;
4240068Smarc 
4357843Smckusick /*
4457843Smckusick  * Locking and stats
4557843Smckusick  */
4657843Smckusick static struct sysctl_lock {
4757843Smckusick 	int	sl_lock;
4857843Smckusick 	int	sl_want;
4957843Smckusick 	int	sl_locked;
5057843Smckusick } memlock;
5157843Smckusick 
5257843Smckusick struct sysctl_args {
5357843Smckusick 	int	*name;
5457843Smckusick 	u_int	namelen;
5557843Smckusick 	void	*old;
5658466Sbostic 	size_t	*oldlenp;
5757843Smckusick 	void	*new;
5858466Sbostic 	size_t	newlen;
5954923Storek };
6057843Smckusick 
6157843Smckusick sysctl(p, uap, retval)
6243444Smckusick 	struct proc *p;
6357843Smckusick 	register struct sysctl_args *uap;
6443444Smckusick 	int *retval;
6543444Smckusick {
6657843Smckusick 	int error, dolock = 1;
6757843Smckusick 	u_int savelen, oldlen = 0;
6857843Smckusick 	sysctlfn *fn;
6957843Smckusick 	int name[CTL_MAXNAME];
7039963Smarc 
7157843Smckusick 	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
7257843Smckusick 		return (error);
7357843Smckusick 	/*
7457843Smckusick 	 * all top-level sysctl names are non-terminal
7557843Smckusick 	 */
7657843Smckusick 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
7757843Smckusick 		return (EINVAL);
7857843Smckusick 	if (error = copyin(uap->name, &name, uap->namelen * sizeof(int)))
7957843Smckusick 		return (error);
8039963Smarc 
8157843Smckusick 	switch (name[0]) {
8257843Smckusick 	case CTL_KERN:
8357843Smckusick 		fn = kern_sysctl;
8457843Smckusick 		if (name[2] != KERN_VNODE)	/* XXX */
8557843Smckusick 			dolock = 0;
8639963Smarc 		break;
8757843Smckusick 	case CTL_HW:
8857843Smckusick 		fn = hw_sysctl;
8940068Smarc 		break;
9057843Smckusick 	case CTL_VM:
9157843Smckusick 		fn = vm_sysctl;
9241181Smarc 		break;
9357843Smckusick 	case CTL_NET:
9457843Smckusick 		fn = net_sysctl;
9550149Smarc 		break;
9657843Smckusick #ifdef notyet
9757843Smckusick 	case CTL_FS:
9857843Smckusick 		fn = fs_sysctl;
9950909Smckusick 		break;
10057843Smckusick 	case CTL_MACHDEP:
10157843Smckusick 		fn = cpu_sysctl;
10252669Smckusick 		break;
10357843Smckusick #endif
10459161Smckusick #ifdef DEBUG
10559161Smckusick 	case CTL_DEBUG:
10659161Smckusick 		fn = debug_sysctl;
10759161Smckusick 		break;
10859161Smckusick #endif
10939963Smarc 	default:
11057843Smckusick 		return (EOPNOTSUPP);
11139963Smarc 	}
11257843Smckusick 
11357843Smckusick 	if (uap->oldlenp &&
11457843Smckusick 	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
11557843Smckusick 		return (error);
11657843Smckusick 	if (uap->old != NULL) {
11757843Smckusick 		if (!useracc(uap->old, oldlen, B_WRITE))
11857843Smckusick 			return (EFAULT);
11957843Smckusick 		while (memlock.sl_lock) {
12057843Smckusick 			memlock.sl_want = 1;
12157843Smckusick 			sleep((caddr_t)&memlock, PRIBIO+1);
12257843Smckusick 			memlock.sl_locked++;
12357843Smckusick 		}
12457843Smckusick 		memlock.sl_lock = 1;
12557843Smckusick 		if (dolock)
12657843Smckusick 			vslock(uap->old, oldlen);
12757843Smckusick 		savelen = oldlen;
12840813Smarc 	}
12957843Smckusick 	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
13058415Smckusick 	    uap->new, uap->newlen, p);
13157843Smckusick 	if (uap->old != NULL) {
13257843Smckusick 		if (dolock)
13357843Smckusick 			vsunlock(uap->old, savelen, B_WRITE);
13457843Smckusick 		memlock.sl_lock = 0;
13557843Smckusick 		if (memlock.sl_want) {
13657843Smckusick 			memlock.sl_want = 0;
13757843Smckusick 			wakeup((caddr_t)&memlock);
13857843Smckusick 		}
13940206Smarc 	}
14057843Smckusick 	if (error)
14157843Smckusick 		return (error);
14257843Smckusick 	if (uap->oldlenp)
14357843Smckusick 		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
14457843Smckusick 	*retval = oldlen;
14557843Smckusick 	return (0);
14657843Smckusick }
14740206Smarc 
14857843Smckusick /*
14957843Smckusick  * Attributes stored in the kernel.
15057843Smckusick  */
15157843Smckusick char hostname[MAXHOSTNAMELEN];
15257843Smckusick int hostnamelen;
15357843Smckusick long hostid;
15458415Smckusick int securelevel;
15557843Smckusick 
15658415Smckusick /*
15758415Smckusick  * kernel related system variables.
15858415Smckusick  */
15958415Smckusick kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
16057843Smckusick 	int *name;
16157843Smckusick 	u_int namelen;
16257843Smckusick 	void *oldp;
16358466Sbostic 	size_t *oldlenp;
16457843Smckusick 	void *newp;
16558466Sbostic 	size_t newlen;
16658415Smckusick 	struct proc *p;
16757843Smckusick {
16858415Smckusick 	int error, level;
16957843Smckusick 	extern char ostype[], osrelease[], version[];
17057843Smckusick 
17157843Smckusick 	/* all sysctl names at this level are terminal */
17259312Smckusick 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
17357843Smckusick 		return (ENOTDIR);		/* overloaded */
17457843Smckusick 
17557843Smckusick 	switch (name[0]) {
17657843Smckusick 	case KERN_OSTYPE:
17757843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
17857843Smckusick 	case KERN_OSRELEASE:
17957843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
18057843Smckusick 	case KERN_OSREV:
18157843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
18257843Smckusick 	case KERN_VERSION:
18357843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, version));
18457843Smckusick 	case KERN_POSIX1:
18557843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
18657843Smckusick 	case KERN_MAXPROC:
18757843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
18857843Smckusick 	case KERN_MAXFILES:
18957843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
190*59314Smckusick 	case KERN_MAXVNODES:
191*59314Smckusick 		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
19257843Smckusick 	case KERN_ARGMAX:
19357843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
19457843Smckusick 	case KERN_HOSTNAME:
19559312Smckusick 		error = sysctl_string(oldp, oldlenp, newp, newlen,
19657843Smckusick 		    hostname, sizeof(hostname));
19757843Smckusick 		if (!error)
19857843Smckusick 			hostnamelen = newlen;
19957843Smckusick 		return (error);
20057843Smckusick 	case KERN_HOSTID:
20157843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &hostid));
20258415Smckusick 	case KERN_SECURELVL:
20358415Smckusick 		level = securelevel;
20458415Smckusick 		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
20558415Smckusick 		    newp == NULL)
20658415Smckusick 			return (error);
20758415Smckusick 		if (level < securelevel && p->p_pid != 1)
20858415Smckusick 			return (EPERM);
20958415Smckusick 		securelevel = level;
21058415Smckusick 		return (0);
21157843Smckusick 	case KERN_CLOCKRATE:
21257843Smckusick 		return (sysctl_clockrate(oldp, oldlenp));
21357843Smckusick 	case KERN_FILE:
21457843Smckusick 		return (sysctl_file(oldp, oldlenp));
21557843Smckusick 	case KERN_VNODE:
21657843Smckusick 		return (sysctl_vnode(oldp, oldlenp));
21757843Smckusick 	case KERN_PROC:
21857843Smckusick 		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
21959312Smckusick #ifdef GPROF
22059312Smckusick 	case KERN_PROF:
22159312Smckusick 		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
22259312Smckusick 		    newp, newlen));
22359312Smckusick #endif
22457843Smckusick 	default:
22557843Smckusick 		return (EOPNOTSUPP);
22652405Storek 	}
22757843Smckusick 	/* NOTREACHED */
22857843Smckusick }
22957843Smckusick 
23058415Smckusick /*
23158415Smckusick  * hardware related system variables.
23258415Smckusick  */
23358415Smckusick hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
23457843Smckusick 	int *name;
23557843Smckusick 	u_int namelen;
23657843Smckusick 	void *oldp;
23758466Sbostic 	size_t *oldlenp;
23857843Smckusick 	void *newp;
23958466Sbostic 	size_t newlen;
24058415Smckusick 	struct proc *p;
24157843Smckusick {
24257843Smckusick 	extern char machine[], cpu_model[];
24357843Smckusick 
24457843Smckusick 	/* all sysctl names at this level are terminal */
24557843Smckusick 	if (namelen != 1)
24657843Smckusick 		return (ENOTDIR);		/* overloaded */
24757843Smckusick 
24857843Smckusick 	switch (name[0]) {
24957843Smckusick 	case HW_MACHINE:
25057843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
25157843Smckusick 	case HW_MODEL:
25257843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
25357843Smckusick 	case HW_NCPU:
25457843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
25557843Smckusick 	case HW_CPUSPEED:
25657843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, cpuspeed));
25757843Smckusick 	case HW_PHYSMEM:
25857843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
25957843Smckusick 	case HW_USERMEM:
26057843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp,
26157843Smckusick 		    ctob(physmem - cnt.v_wire_count)));
26257843Smckusick 	case HW_PAGESIZE:
26357843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
26457843Smckusick 	default:
26557843Smckusick 		return (EOPNOTSUPP);
26657843Smckusick 	}
26757843Smckusick 	/* NOTREACHED */
26857843Smckusick }
26957843Smckusick 
27059161Smckusick #ifdef DEBUG
27157843Smckusick /*
27259161Smckusick  * Debugging related system variables.
27359161Smckusick  */
27459161Smckusick struct ctldebug debug0, debug1, debug2, debug3, debug4;
27559161Smckusick struct ctldebug debug5, debug6, debug7, debug8, debug9;
27659161Smckusick struct ctldebug debug10, debug11, debug12, debug13, debug14;
27759161Smckusick struct ctldebug debug15, debug16, debug17, debug18, debug19;
27859161Smckusick static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
27959161Smckusick 	&debug0, &debug1, &debug2, &debug3, &debug4,
28059161Smckusick 	&debug5, &debug6, &debug7, &debug8, &debug9,
28159161Smckusick 	&debug10, &debug11, &debug12, &debug13, &debug14,
28259161Smckusick 	&debug15, &debug16, &debug17, &debug18, &debug19,
28359161Smckusick };
28459161Smckusick int
28559161Smckusick debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
28659161Smckusick 	int *name;
28759161Smckusick 	u_int namelen;
28859161Smckusick 	void *oldp;
28959161Smckusick 	size_t *oldlenp;
29059161Smckusick 	void *newp;
29159161Smckusick 	size_t newlen;
29259161Smckusick 	struct proc *p;
29359161Smckusick {
29459161Smckusick 	struct ctldebug *cdp;
29559161Smckusick 
29659161Smckusick 	/* all sysctl names at this level are name and field */
29759161Smckusick 	if (namelen != 2)
29859161Smckusick 		return (ENOTDIR);		/* overloaded */
29959161Smckusick 	cdp = debugvars[name[0]];
30059161Smckusick 	if (cdp->debugname == 0)
30159161Smckusick 		return (EOPNOTSUPP);
30259161Smckusick 	switch (name[1]) {
30359161Smckusick 	case CTL_DEBUG_NAME:
30459161Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
30559161Smckusick 	case CTL_DEBUG_VALUE:
30659161Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
30759161Smckusick 	default:
30859161Smckusick 		return (EOPNOTSUPP);
30959161Smckusick 	}
31059161Smckusick 	/* NOTREACHED */
31159161Smckusick }
31259161Smckusick #endif /* DEBUG */
31359161Smckusick 
31459161Smckusick /*
31557843Smckusick  * Validate parameters and get old / set new parameters
31657843Smckusick  * for an integer-valued sysctl function.
31757843Smckusick  */
31857843Smckusick sysctl_int(oldp, oldlenp, newp, newlen, valp)
31957843Smckusick 	void *oldp;
32058466Sbostic 	size_t *oldlenp;
32157843Smckusick 	void *newp;
32258466Sbostic 	size_t newlen;
32357843Smckusick 	int *valp;
32457843Smckusick {
32557843Smckusick 	int error = 0;
32657843Smckusick 
32757843Smckusick 	if (oldp && *oldlenp < sizeof(int))
32857843Smckusick 		return (ENOMEM);
32957843Smckusick 	if (newp && newlen != sizeof(int))
33057843Smckusick 		return (EINVAL);
33157843Smckusick 	*oldlenp = sizeof(int);
33257843Smckusick 	if (oldp)
33357843Smckusick 		error = copyout(valp, oldp, sizeof(int));
33457843Smckusick 	if (error == 0 && newp)
33557843Smckusick 		error = copyin(newp, valp, sizeof(int));
33643444Smckusick 	return (error);
33739963Smarc }
33839963Smarc 
33957843Smckusick /*
34057843Smckusick  * As above, but read-only.
34157843Smckusick  */
34257843Smckusick sysctl_rdint(oldp, oldlenp, newp, val)
34357843Smckusick 	void *oldp;
34458466Sbostic 	size_t *oldlenp;
34557843Smckusick 	void *newp;
34657843Smckusick 	int val;
34757843Smckusick {
34857843Smckusick 	int error = 0;
34957843Smckusick 
35057843Smckusick 	if (oldp && *oldlenp < sizeof(int))
35157843Smckusick 		return (ENOMEM);
35257843Smckusick 	if (newp)
35357843Smckusick 		return (EPERM);
35457843Smckusick 	*oldlenp = sizeof(int);
35557843Smckusick 	if (oldp)
35657843Smckusick 		error = copyout((caddr_t)&val, oldp, sizeof(int));
35757843Smckusick 	return (error);
35857843Smckusick }
35957843Smckusick 
36057843Smckusick /*
36157843Smckusick  * Validate parameters and get old / set new parameters
36257843Smckusick  * for a string-valued sysctl function.
36357843Smckusick  */
36457843Smckusick sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
36557843Smckusick 	void *oldp;
36658466Sbostic 	size_t *oldlenp;
36757843Smckusick 	void *newp;
36858466Sbostic 	size_t newlen;
36957843Smckusick 	char *str;
37057843Smckusick 	int maxlen;
37157843Smckusick {
37257843Smckusick 	int len, error = 0;
37357843Smckusick 
37457843Smckusick 	len = strlen(str) + 1;
37557843Smckusick 	if (oldp && *oldlenp < len)
37657843Smckusick 		return (ENOMEM);
37757843Smckusick 	if (newp && newlen >= maxlen)
37857843Smckusick 		return (EINVAL);
37958128Sralph 	if (oldp) {
38058128Sralph 		*oldlenp = len;
38157843Smckusick 		error = copyout(str, oldp, len);
38258128Sralph 	}
38357843Smckusick 	if (error == 0 && newp) {
38457843Smckusick 		error = copyin(newp, str, newlen);
38557843Smckusick 		str[newlen] = 0;
38657843Smckusick 	}
38757843Smckusick 	return (error);
38857843Smckusick }
38957843Smckusick 
39057843Smckusick /*
39157843Smckusick  * As above, but read-only.
39257843Smckusick  */
39357843Smckusick sysctl_rdstring(oldp, oldlenp, newp, str)
39457843Smckusick 	void *oldp;
39558466Sbostic 	size_t *oldlenp;
39657843Smckusick 	void *newp;
39757843Smckusick 	char *str;
39857843Smckusick {
39957843Smckusick 	int len, error = 0;
40057843Smckusick 
40157843Smckusick 	len = strlen(str) + 1;
40257843Smckusick 	if (oldp && *oldlenp < len)
40357843Smckusick 		return (ENOMEM);
40457843Smckusick 	if (newp)
40557843Smckusick 		return (EPERM);
40657843Smckusick 	*oldlenp = len;
40757843Smckusick 	if (oldp)
40857843Smckusick 		error = copyout(str, oldp, len);
40957843Smckusick 	return (error);
41057843Smckusick }
41157843Smckusick 
41257843Smckusick /*
41359312Smckusick  * Validate parameters and get old / set new parameters
41459312Smckusick  * for a structure oriented sysctl function.
41559312Smckusick  */
41659312Smckusick sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
41759312Smckusick 	void *oldp;
41859312Smckusick 	size_t *oldlenp;
41959312Smckusick 	void *newp;
42059312Smckusick 	size_t newlen;
42159312Smckusick 	void *sp;
42259312Smckusick 	int len;
42359312Smckusick {
42459312Smckusick 	int error = 0;
42559312Smckusick 
42659312Smckusick 	if (oldp && *oldlenp < len)
42759312Smckusick 		return (ENOMEM);
42859312Smckusick 	if (newp && newlen > len)
42959312Smckusick 		return (EINVAL);
43059312Smckusick 	if (oldp) {
43159312Smckusick 		*oldlenp = len;
43259312Smckusick 		error = copyout(sp, oldp, len);
43359312Smckusick 	}
43459312Smckusick 	if (error == 0 && newp)
43559312Smckusick 		error = copyin(newp, sp, len);
43659312Smckusick 	return (error);
43759312Smckusick }
43859312Smckusick 
43959312Smckusick /*
44057843Smckusick  * Validate parameters and get old parameters
44157843Smckusick  * for a structure oriented sysctl function.
44257843Smckusick  */
44357843Smckusick sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
44457843Smckusick 	void *oldp;
44558466Sbostic 	size_t *oldlenp;
44658466Sbostic 	void *newp, *sp;
44757843Smckusick 	int len;
44857843Smckusick {
44957843Smckusick 	int error = 0;
45057843Smckusick 
45157843Smckusick 	if (oldp && *oldlenp < len)
45257843Smckusick 		return (ENOMEM);
45357843Smckusick 	if (newp)
45457843Smckusick 		return (EPERM);
45557843Smckusick 	*oldlenp = len;
45657843Smckusick 	if (oldp)
45757843Smckusick 		error = copyout(sp, oldp, len);
45857843Smckusick 	return (error);
45957843Smckusick }
46057843Smckusick 
46157843Smckusick /*
46257843Smckusick  * Get file structures.
46357843Smckusick  */
46457843Smckusick sysctl_file(where, sizep)
46557843Smckusick 	char *where;
46658466Sbostic 	size_t *sizep;
46757843Smckusick {
46857843Smckusick 	int buflen, error;
46957843Smckusick 	struct file *fp;
47057843Smckusick 	char *start = where;
47157843Smckusick 
47257843Smckusick 	buflen = *sizep;
47357843Smckusick 	if (where == NULL) {
47457843Smckusick 		/*
47557843Smckusick 		 * overestimate by 10 files
47657843Smckusick 		 */
47757843Smckusick 		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
47857843Smckusick 		return (0);
47957843Smckusick 	}
48057843Smckusick 
48157843Smckusick 	/*
48257843Smckusick 	 * first copyout filehead
48357843Smckusick 	 */
48457843Smckusick 	if (buflen < sizeof(filehead)) {
48557843Smckusick 		*sizep = 0;
48657843Smckusick 		return (0);
48757843Smckusick 	}
48857843Smckusick 	if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
48957843Smckusick 		return (error);
49057843Smckusick 	buflen += sizeof(filehead);
49157843Smckusick 	where += sizeof(filehead);
49257843Smckusick 
49357843Smckusick 	/*
49457843Smckusick 	 * followed by an array of file structures
49557843Smckusick 	 */
49657843Smckusick 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
49757843Smckusick 		if (buflen < sizeof(struct file)) {
49857843Smckusick 			*sizep = where - start;
49957843Smckusick 			return (ENOMEM);
50057843Smckusick 		}
50157843Smckusick 		if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
50257843Smckusick 			return (error);
50357843Smckusick 		buflen -= sizeof(struct file);
50457843Smckusick 		where += sizeof(struct file);
50557843Smckusick 	}
50657843Smckusick 	*sizep = where - start;
50757843Smckusick 	return (0);
50857843Smckusick }
50957843Smckusick 
51059312Smckusick /*
51159312Smckusick  * try over estimating by 5 procs
51239963Smarc  */
51357843Smckusick #define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
51439963Smarc 
51557843Smckusick sysctl_doproc(name, namelen, where, sizep)
51657843Smckusick 	int *name;
51758466Sbostic 	u_int namelen;
51839963Smarc 	char *where;
51958466Sbostic 	size_t *sizep;
52039963Smarc {
52139963Smarc 	register struct proc *p;
52243419Smarc 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
52357843Smckusick 	register int needed = 0;
52457843Smckusick 	int buflen = where != NULL ? *sizep : 0;
52539963Smarc 	int doingzomb;
52640067Smarc 	struct eproc eproc;
52739963Smarc 	int error = 0;
52839963Smarc 
52957843Smckusick 	if (namelen != 2)
53057843Smckusick 		return (EINVAL);
53154755Storek 	p = (struct proc *)allproc;
53239963Smarc 	doingzomb = 0;
53339963Smarc again:
53439963Smarc 	for (; p != NULL; p = p->p_nxt) {
53553819Smckusick 		/*
53653819Smckusick 		 * Skip embryonic processes.
53753819Smckusick 		 */
53853819Smckusick 		if (p->p_stat == SIDL)
53953819Smckusick 			continue;
54059312Smckusick 		/*
54139963Smarc 		 * TODO - make more efficient (see notes below).
54259312Smckusick 		 * do by session.
54339963Smarc 		 */
54457843Smckusick 		switch (name[0]) {
54539963Smarc 
54657843Smckusick 		case KERN_PROC_PID:
54739963Smarc 			/* could do this with just a lookup */
54857843Smckusick 			if (p->p_pid != (pid_t)name[1])
54939963Smarc 				continue;
55039963Smarc 			break;
55139963Smarc 
55257843Smckusick 		case KERN_PROC_PGRP:
55339963Smarc 			/* could do this by traversing pgrp */
55457843Smckusick 			if (p->p_pgrp->pg_id != (pid_t)name[1])
55539963Smarc 				continue;
55639963Smarc 			break;
55739963Smarc 
55857843Smckusick 		case KERN_PROC_TTY:
55959312Smckusick 			if ((p->p_flag&SCTTY) == 0 ||
56039963Smarc 			    p->p_session->s_ttyp == NULL ||
56157843Smckusick 			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
56239963Smarc 				continue;
56339963Smarc 			break;
56439963Smarc 
56557843Smckusick 		case KERN_PROC_UID:
56657843Smckusick 			if (p->p_ucred->cr_uid != (uid_t)name[1])
56739963Smarc 				continue;
56839963Smarc 			break;
56939963Smarc 
57057843Smckusick 		case KERN_PROC_RUID:
57157843Smckusick 			if (p->p_cred->p_ruid != (uid_t)name[1])
57239963Smarc 				continue;
57339963Smarc 			break;
57439963Smarc 		}
57557843Smckusick 		if (buflen >= sizeof(struct kinfo_proc)) {
57648407Skarels 			fill_eproc(p, &eproc);
57759312Smckusick 			if (error = copyout((caddr_t)p, &dp->kp_proc,
57857843Smckusick 			    sizeof(struct proc)))
57939963Smarc 				return (error);
58059312Smckusick 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
58157843Smckusick 			    sizeof(eproc)))
58239963Smarc 				return (error);
58343419Smarc 			dp++;
58457843Smckusick 			buflen -= sizeof(struct kinfo_proc);
58539963Smarc 		}
58657843Smckusick 		needed += sizeof(struct kinfo_proc);
58739963Smarc 	}
58839963Smarc 	if (doingzomb == 0) {
58939963Smarc 		p = zombproc;
59039963Smarc 		doingzomb++;
59139963Smarc 		goto again;
59239963Smarc 	}
59357843Smckusick 	if (where != NULL) {
59457843Smckusick 		*sizep = (caddr_t)dp - where;
59557843Smckusick 		if (needed > *sizep)
59657843Smckusick 			return (ENOMEM);
59757843Smckusick 	} else {
59857843Smckusick 		needed += KERN_PROCSLOP;
59957843Smckusick 		*sizep = needed;
60057843Smckusick 	}
60139963Smarc 	return (0);
60239963Smarc }
60348407Skarels 
60448407Skarels /*
60548407Skarels  * Fill in an eproc structure for the specified process.
60648407Skarels  */
60748407Skarels void
60848407Skarels fill_eproc(p, ep)
60948407Skarels 	register struct proc *p;
61048407Skarels 	register struct eproc *ep;
61148407Skarels {
61248407Skarels 	register struct tty *tp;
61348407Skarels 
61448407Skarels 	ep->e_paddr = p;
61548407Skarels 	ep->e_sess = p->p_pgrp->pg_session;
61648407Skarels 	ep->e_pcred = *p->p_cred;
61748407Skarels 	ep->e_ucred = *p->p_ucred;
61852405Storek 	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
61952405Storek 		ep->e_vm.vm_rssize = 0;
62052405Storek 		ep->e_vm.vm_tsize = 0;
62152405Storek 		ep->e_vm.vm_dsize = 0;
62252405Storek 		ep->e_vm.vm_ssize = 0;
62352405Storek #ifndef sparc
62452405Storek 		/* ep->e_vm.vm_pmap = XXX; */
62552405Storek #endif
62652405Storek 	} else {
62752405Storek 		register struct vmspace *vm = p->p_vmspace;
62852405Storek 
62952405Storek 		ep->e_vm.vm_rssize = vm->vm_rssize;
63052405Storek 		ep->e_vm.vm_tsize = vm->vm_tsize;
63152405Storek 		ep->e_vm.vm_dsize = vm->vm_dsize;
63252405Storek 		ep->e_vm.vm_ssize = vm->vm_ssize;
63352405Storek #ifndef sparc
63452405Storek 		ep->e_vm.vm_pmap = vm->vm_pmap;
63552405Storek #endif
63652405Storek 	}
63749141Skarels 	if (p->p_pptr)
63849141Skarels 		ep->e_ppid = p->p_pptr->p_pid;
63949141Skarels 	else
64049141Skarels 		ep->e_ppid = 0;
64148407Skarels 	ep->e_pgid = p->p_pgrp->pg_id;
64248407Skarels 	ep->e_jobc = p->p_pgrp->pg_jobc;
64359312Smckusick 	if ((p->p_flag&SCTTY) &&
64448407Skarels 	     (tp = ep->e_sess->s_ttyp)) {
64548407Skarels 		ep->e_tdev = tp->t_dev;
64650022Skarels 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
64748407Skarels 		ep->e_tsess = tp->t_session;
64848407Skarels 	} else
64948407Skarels 		ep->e_tdev = NODEV;
65048407Skarels 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
65148407Skarels 	if (SESS_LEADER(p))
65248407Skarels 		ep->e_flag |= EPROC_SLEADER;
65348407Skarels 	if (p->p_wmesg)
65448407Skarels 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
65548407Skarels 	ep->e_xsize = ep->e_xrssize = 0;
65648407Skarels 	ep->e_xccount = ep->e_xswrss = 0;
65748407Skarels }
65850149Smarc 
65957843Smckusick #ifdef COMPAT_43
66057843Smckusick #include <sys/socket.h>
66157906Smckusick #define	KINFO_PROC		(0<<8)
66257906Smckusick #define	KINFO_RT		(1<<8)
66357906Smckusick #define	KINFO_VNODE		(2<<8)
66457906Smckusick #define	KINFO_FILE		(3<<8)
66557906Smckusick #define	KINFO_METER		(4<<8)
66657906Smckusick #define	KINFO_LOADAVG		(5<<8)
66757906Smckusick #define	KINFO_CLOCKRATE		(6<<8)
66857843Smckusick 
66957843Smckusick struct getkerninfo_args {
67057843Smckusick 	int	op;
67157843Smckusick 	char	*where;
67257843Smckusick 	int	*size;
67357843Smckusick 	int	arg;
67457843Smckusick };
67557843Smckusick 
67658943Smckusick ogetkerninfo(p, uap, retval)
67757843Smckusick 	struct proc *p;
67857843Smckusick 	register struct getkerninfo_args *uap;
67957843Smckusick 	int *retval;
68050149Smarc {
68157843Smckusick 	int error, name[5];
68257843Smckusick 	u_int size;
68350149Smarc 
68458461Smckusick 	if (uap->size &&
68558466Sbostic 	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
68657843Smckusick 		return (error);
68750149Smarc 
68857906Smckusick 	switch (uap->op & 0xff00) {
68950149Smarc 
69057843Smckusick 	case KINFO_RT:
69157843Smckusick 		name[0] = PF_ROUTE;
69257843Smckusick 		name[1] = 0;
69357843Smckusick 		name[2] = (uap->op & 0xff0000) >> 16;
69457843Smckusick 		name[3] = uap->op & 0xff;
69557843Smckusick 		name[4] = uap->arg;
69658415Smckusick 		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
69757843Smckusick 		break;
69857843Smckusick 
69957843Smckusick 	case KINFO_VNODE:
70057843Smckusick 		name[0] = KERN_VNODE;
70158415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
70257843Smckusick 		break;
70357843Smckusick 
70457843Smckusick 	case KINFO_PROC:
70557843Smckusick 		name[0] = KERN_PROC;
70657843Smckusick 		name[1] = uap->op & 0xff;
70757843Smckusick 		name[2] = uap->arg;
70858415Smckusick 		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
70957843Smckusick 		break;
71057843Smckusick 
71157843Smckusick 	case KINFO_FILE:
71257843Smckusick 		name[0] = KERN_FILE;
71358415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
71457843Smckusick 		break;
71557843Smckusick 
71657843Smckusick 	case KINFO_METER:
71757843Smckusick 		name[0] = VM_METER;
71858415Smckusick 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
71957843Smckusick 		break;
72057843Smckusick 
72157843Smckusick 	case KINFO_LOADAVG:
72257843Smckusick 		name[0] = VM_LOADAVG;
72358415Smckusick 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
72457843Smckusick 		break;
72557843Smckusick 
72657843Smckusick 	case KINFO_CLOCKRATE:
72757843Smckusick 		name[0] = KERN_CLOCKRATE;
72858415Smckusick 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
72957843Smckusick 		break;
73057843Smckusick 
73157843Smckusick 	default:
73258415Smckusick 		return (EOPNOTSUPP);
73350149Smarc 	}
73457843Smckusick 	if (error)
73557843Smckusick 		return (error);
73657843Smckusick 	*retval = size;
73758461Smckusick 	if (uap->size)
73858461Smckusick 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
73958461Smckusick 		    sizeof(size));
74058461Smckusick 	return (error);
74150149Smarc }
74257843Smckusick #endif /* COMPAT_43 */
743