xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 68298)
157843Smckusick /*-
263457Sbostic  * Copyright (c) 1982, 1986, 1989, 1993
363457Sbostic  *	The Regents of the University of California.  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*68298Scgd  *	@(#)kern_sysctl.c	8.7 (Berkeley) 02/14/95
1139963Smarc  */
1239963Smarc 
1357843Smckusick /*
1457843Smckusick  * sysctl system call.
1557843Smckusick  */
1657843Smckusick 
1756517Sbostic #include <sys/param.h>
1857843Smckusick #include <sys/systm.h>
1960153Smckusick #include <sys/kernel.h>
2057843Smckusick #include <sys/malloc.h>
2156517Sbostic #include <sys/proc.h>
2257843Smckusick #include <sys/file.h>
2359314Smckusick #include <sys/vnode.h>
2457843Smckusick #include <sys/unistd.h>
2557843Smckusick #include <sys/buf.h>
2656517Sbostic #include <sys/ioctl.h>
2756517Sbostic #include <sys/tty.h>
2856517Sbostic #include <vm/vm.h>
2959354Smckusick #include <sys/sysctl.h>
3048407Skarels 
31*68298Scgd #include <sys/mount.h>
32*68298Scgd #include <sys/syscallargs.h>
33*68298Scgd 
3457843Smckusick sysctlfn kern_sysctl;
3557843Smckusick sysctlfn hw_sysctl;
3659161Smckusick #ifdef DEBUG
3759161Smckusick sysctlfn debug_sysctl;
3859161Smckusick #endif
3957843Smckusick extern sysctlfn vm_sysctl;
4057843Smckusick extern sysctlfn fs_sysctl;
4157843Smckusick extern sysctlfn net_sysctl;
4257843Smckusick extern sysctlfn cpu_sysctl;
4340068Smarc 
4457843Smckusick /*
4557843Smckusick  * Locking and stats
4657843Smckusick  */
4757843Smckusick static struct sysctl_lock {
4857843Smckusick 	int	sl_lock;
4957843Smckusick 	int	sl_want;
5057843Smckusick 	int	sl_locked;
5157843Smckusick } memlock;
5257843Smckusick 
5359718Sbostic int
5459718Sbostic __sysctl(p, uap, retval)
5543444Smckusick 	struct proc *p;
56*68298Scgd 	register struct __sysctl_args /* {
57*68298Scgd 		syscallarg(int *) name;
58*68298Scgd 		syscallarg(u_int) namelen;
59*68298Scgd 		syscallarg(void *) old;
60*68298Scgd 		syscallarg(size_t *) oldlenp;
61*68298Scgd 		syscallarg(void *) new;
62*68298Scgd 		syscallarg(size_t) newlen;
63*68298Scgd 	} */ *uap;
64*68298Scgd 	register_t *retval;
6543444Smckusick {
6657843Smckusick 	int error, dolock = 1;
67*68298Scgd 	size_t savelen, oldlen = 0;
6857843Smckusick 	sysctlfn *fn;
6957843Smckusick 	int name[CTL_MAXNAME];
7039963Smarc 
71*68298Scgd 	if (SCARG(uap, new) != NULL &&
72*68298Scgd 	    (error = suser(p->p_ucred, &p->p_acflag)))
7357843Smckusick 		return (error);
7457843Smckusick 	/*
7557843Smckusick 	 * all top-level sysctl names are non-terminal
7657843Smckusick 	 */
77*68298Scgd 	if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2)
7857843Smckusick 		return (EINVAL);
79*68298Scgd 	if (error =
80*68298Scgd 	    copyin(SCARG(uap, name), &name, SCARG(uap, namelen) * sizeof(int)))
8157843Smckusick 		return (error);
8239963Smarc 
8357843Smckusick 	switch (name[0]) {
8457843Smckusick 	case CTL_KERN:
8557843Smckusick 		fn = kern_sysctl;
8668192Smckusick 		if (name[2] == KERN_VNODE)	/* XXX */
8757843Smckusick 			dolock = 0;
8839963Smarc 		break;
8957843Smckusick 	case CTL_HW:
9057843Smckusick 		fn = hw_sysctl;
9140068Smarc 		break;
9257843Smckusick 	case CTL_VM:
9357843Smckusick 		fn = vm_sysctl;
9441181Smarc 		break;
9557843Smckusick 	case CTL_NET:
9657843Smckusick 		fn = net_sysctl;
9750149Smarc 		break;
9857843Smckusick #ifdef notyet
9957843Smckusick 	case CTL_FS:
10057843Smckusick 		fn = fs_sysctl;
10150909Smckusick 		break;
10260171Smckusick #endif
10357843Smckusick 	case CTL_MACHDEP:
10457843Smckusick 		fn = cpu_sysctl;
10552669Smckusick 		break;
10659161Smckusick #ifdef DEBUG
10759161Smckusick 	case CTL_DEBUG:
10859161Smckusick 		fn = debug_sysctl;
10959161Smckusick 		break;
11059161Smckusick #endif
11139963Smarc 	default:
11257843Smckusick 		return (EOPNOTSUPP);
11339963Smarc 	}
11457843Smckusick 
115*68298Scgd 	if (SCARG(uap, oldlenp) &&
116*68298Scgd 	    (error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen))))
11757843Smckusick 		return (error);
118*68298Scgd 	if (SCARG(uap, old) != NULL) {
119*68298Scgd 		if (!useracc(SCARG(uap, old), oldlen, B_WRITE))
12057843Smckusick 			return (EFAULT);
12157843Smckusick 		while (memlock.sl_lock) {
12257843Smckusick 			memlock.sl_want = 1;
12357843Smckusick 			sleep((caddr_t)&memlock, PRIBIO+1);
12457843Smckusick 			memlock.sl_locked++;
12557843Smckusick 		}
12657843Smckusick 		memlock.sl_lock = 1;
12757843Smckusick 		if (dolock)
128*68298Scgd 			vslock(SCARG(uap, old), oldlen);
12957843Smckusick 		savelen = oldlen;
13040813Smarc 	}
131*68298Scgd 	error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old),
132*68298Scgd 	    &oldlen, SCARG(uap, new), SCARG(uap, newlen), p);
133*68298Scgd 	if (SCARG(uap, old) != NULL) {
13457843Smckusick 		if (dolock)
135*68298Scgd 			vsunlock(SCARG(uap, old), savelen, B_WRITE);
13657843Smckusick 		memlock.sl_lock = 0;
13757843Smckusick 		if (memlock.sl_want) {
13857843Smckusick 			memlock.sl_want = 0;
13957843Smckusick 			wakeup((caddr_t)&memlock);
14057843Smckusick 		}
14140206Smarc 	}
14257843Smckusick 	if (error)
14357843Smckusick 		return (error);
144*68298Scgd 	if (SCARG(uap, oldlenp))
145*68298Scgd 		error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen));
14657843Smckusick 	*retval = oldlen;
14757843Smckusick 	return (0);
14857843Smckusick }
14940206Smarc 
15057843Smckusick /*
15157843Smckusick  * Attributes stored in the kernel.
15257843Smckusick  */
15357843Smckusick char hostname[MAXHOSTNAMELEN];
15457843Smckusick int hostnamelen;
15557843Smckusick long hostid;
15658415Smckusick int securelevel;
15757843Smckusick 
15858415Smckusick /*
15958415Smckusick  * kernel related system variables.
16058415Smckusick  */
16158415Smckusick kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
16257843Smckusick 	int *name;
16357843Smckusick 	u_int namelen;
16457843Smckusick 	void *oldp;
16558466Sbostic 	size_t *oldlenp;
16657843Smckusick 	void *newp;
16758466Sbostic 	size_t newlen;
16858415Smckusick 	struct proc *p;
16957843Smckusick {
17063456Smckusick 	int error, level, inthostid;
17157843Smckusick 	extern char ostype[], osrelease[], version[];
17257843Smckusick 
17357843Smckusick 	/* all sysctl names at this level are terminal */
17459312Smckusick 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
17557843Smckusick 		return (ENOTDIR);		/* overloaded */
17657843Smckusick 
17757843Smckusick 	switch (name[0]) {
17857843Smckusick 	case KERN_OSTYPE:
17957843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
18057843Smckusick 	case KERN_OSRELEASE:
18157843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
18257843Smckusick 	case KERN_OSREV:
18357843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
18457843Smckusick 	case KERN_VERSION:
18557843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, version));
18659718Sbostic 	case KERN_MAXVNODES:
18759718Sbostic 		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
18857843Smckusick 	case KERN_MAXPROC:
18957843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
19057843Smckusick 	case KERN_MAXFILES:
19157843Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
19257843Smckusick 	case KERN_ARGMAX:
19357843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
19458415Smckusick 	case KERN_SECURELVL:
19558415Smckusick 		level = securelevel;
19658415Smckusick 		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
19758415Smckusick 		    newp == NULL)
19858415Smckusick 			return (error);
19958415Smckusick 		if (level < securelevel && p->p_pid != 1)
20058415Smckusick 			return (EPERM);
20158415Smckusick 		securelevel = level;
20258415Smckusick 		return (0);
20359718Sbostic 	case KERN_HOSTNAME:
20459718Sbostic 		error = sysctl_string(oldp, oldlenp, newp, newlen,
20559718Sbostic 		    hostname, sizeof(hostname));
20661302Smckusick 		if (newp && !error)
20759718Sbostic 			hostnamelen = newlen;
20859718Sbostic 		return (error);
20959718Sbostic 	case KERN_HOSTID:
21063456Smckusick 		inthostid = hostid;  /* XXX assumes sizeof long <= sizeof int */
21163456Smckusick 		error =  sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
21263456Smckusick 		hostid = inthostid;
21363456Smckusick 		return (error);
21457843Smckusick 	case KERN_CLOCKRATE:
21557843Smckusick 		return (sysctl_clockrate(oldp, oldlenp));
21660153Smckusick 	case KERN_BOOTTIME:
21760153Smckusick 		return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
21860153Smckusick 		    sizeof(struct timeval)));
21957843Smckusick 	case KERN_VNODE:
22057843Smckusick 		return (sysctl_vnode(oldp, oldlenp));
22157843Smckusick 	case KERN_PROC:
22257843Smckusick 		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
22359718Sbostic 	case KERN_FILE:
22459718Sbostic 		return (sysctl_file(oldp, oldlenp));
22559312Smckusick #ifdef GPROF
22659312Smckusick 	case KERN_PROF:
22759312Smckusick 		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
22859312Smckusick 		    newp, newlen));
22959312Smckusick #endif
23059718Sbostic 	case KERN_POSIX1:
23159718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
23259718Sbostic 	case KERN_NGROUPS:
23359718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
23459718Sbostic 	case KERN_JOB_CONTROL:
23559718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
23659718Sbostic 	case KERN_SAVED_IDS:
23759718Sbostic #ifdef _POSIX_SAVED_IDS
23859718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
23959718Sbostic #else
24059718Sbostic 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
24159718Sbostic #endif
24257843Smckusick 	default:
24357843Smckusick 		return (EOPNOTSUPP);
24452405Storek 	}
24557843Smckusick 	/* NOTREACHED */
24657843Smckusick }
24757843Smckusick 
24858415Smckusick /*
24958415Smckusick  * hardware related system variables.
25058415Smckusick  */
25158415Smckusick hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
25257843Smckusick 	int *name;
25357843Smckusick 	u_int namelen;
25457843Smckusick 	void *oldp;
25558466Sbostic 	size_t *oldlenp;
25657843Smckusick 	void *newp;
25758466Sbostic 	size_t newlen;
25858415Smckusick 	struct proc *p;
25957843Smckusick {
26057843Smckusick 	extern char machine[], cpu_model[];
26157843Smckusick 
26257843Smckusick 	/* all sysctl names at this level are terminal */
26357843Smckusick 	if (namelen != 1)
26457843Smckusick 		return (ENOTDIR);		/* overloaded */
26557843Smckusick 
26657843Smckusick 	switch (name[0]) {
26757843Smckusick 	case HW_MACHINE:
26857843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
26957843Smckusick 	case HW_MODEL:
27057843Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
27157843Smckusick 	case HW_NCPU:
27257843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
27359618Smckusick 	case HW_BYTEORDER:
27459618Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
27557843Smckusick 	case HW_PHYSMEM:
27657843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
27757843Smckusick 	case HW_USERMEM:
27857843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp,
27957843Smckusick 		    ctob(physmem - cnt.v_wire_count)));
28057843Smckusick 	case HW_PAGESIZE:
28157843Smckusick 		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
28257843Smckusick 	default:
28357843Smckusick 		return (EOPNOTSUPP);
28457843Smckusick 	}
28557843Smckusick 	/* NOTREACHED */
28657843Smckusick }
28757843Smckusick 
28859161Smckusick #ifdef DEBUG
28957843Smckusick /*
29059161Smckusick  * Debugging related system variables.
29159161Smckusick  */
29259161Smckusick struct ctldebug debug0, debug1, debug2, debug3, debug4;
29359161Smckusick struct ctldebug debug5, debug6, debug7, debug8, debug9;
29459161Smckusick struct ctldebug debug10, debug11, debug12, debug13, debug14;
29559161Smckusick struct ctldebug debug15, debug16, debug17, debug18, debug19;
29659161Smckusick static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
29759161Smckusick 	&debug0, &debug1, &debug2, &debug3, &debug4,
29859161Smckusick 	&debug5, &debug6, &debug7, &debug8, &debug9,
29959161Smckusick 	&debug10, &debug11, &debug12, &debug13, &debug14,
30059161Smckusick 	&debug15, &debug16, &debug17, &debug18, &debug19,
30159161Smckusick };
30259161Smckusick int
30359161Smckusick debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
30459161Smckusick 	int *name;
30559161Smckusick 	u_int namelen;
30659161Smckusick 	void *oldp;
30759161Smckusick 	size_t *oldlenp;
30859161Smckusick 	void *newp;
30959161Smckusick 	size_t newlen;
31059161Smckusick 	struct proc *p;
31159161Smckusick {
31259161Smckusick 	struct ctldebug *cdp;
31359161Smckusick 
31459161Smckusick 	/* all sysctl names at this level are name and field */
31559161Smckusick 	if (namelen != 2)
31659161Smckusick 		return (ENOTDIR);		/* overloaded */
31759161Smckusick 	cdp = debugvars[name[0]];
31859161Smckusick 	if (cdp->debugname == 0)
31959161Smckusick 		return (EOPNOTSUPP);
32059161Smckusick 	switch (name[1]) {
32159161Smckusick 	case CTL_DEBUG_NAME:
32259161Smckusick 		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
32359161Smckusick 	case CTL_DEBUG_VALUE:
32459161Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
32559161Smckusick 	default:
32659161Smckusick 		return (EOPNOTSUPP);
32759161Smckusick 	}
32859161Smckusick 	/* NOTREACHED */
32959161Smckusick }
33059161Smckusick #endif /* DEBUG */
33159161Smckusick 
33259161Smckusick /*
33357843Smckusick  * Validate parameters and get old / set new parameters
33457843Smckusick  * for an integer-valued sysctl function.
33557843Smckusick  */
33657843Smckusick sysctl_int(oldp, oldlenp, newp, newlen, valp)
33757843Smckusick 	void *oldp;
33858466Sbostic 	size_t *oldlenp;
33957843Smckusick 	void *newp;
34058466Sbostic 	size_t newlen;
34157843Smckusick 	int *valp;
34257843Smckusick {
34357843Smckusick 	int error = 0;
34457843Smckusick 
34557843Smckusick 	if (oldp && *oldlenp < sizeof(int))
34657843Smckusick 		return (ENOMEM);
34757843Smckusick 	if (newp && newlen != sizeof(int))
34857843Smckusick 		return (EINVAL);
34957843Smckusick 	*oldlenp = sizeof(int);
35057843Smckusick 	if (oldp)
35157843Smckusick 		error = copyout(valp, oldp, sizeof(int));
35257843Smckusick 	if (error == 0 && newp)
35357843Smckusick 		error = copyin(newp, valp, sizeof(int));
35443444Smckusick 	return (error);
35539963Smarc }
35639963Smarc 
35757843Smckusick /*
35857843Smckusick  * As above, but read-only.
35957843Smckusick  */
36057843Smckusick sysctl_rdint(oldp, oldlenp, newp, val)
36157843Smckusick 	void *oldp;
36258466Sbostic 	size_t *oldlenp;
36357843Smckusick 	void *newp;
36457843Smckusick 	int val;
36557843Smckusick {
36657843Smckusick 	int error = 0;
36757843Smckusick 
36857843Smckusick 	if (oldp && *oldlenp < sizeof(int))
36957843Smckusick 		return (ENOMEM);
37057843Smckusick 	if (newp)
37157843Smckusick 		return (EPERM);
37257843Smckusick 	*oldlenp = sizeof(int);
37357843Smckusick 	if (oldp)
37457843Smckusick 		error = copyout((caddr_t)&val, oldp, sizeof(int));
37557843Smckusick 	return (error);
37657843Smckusick }
37757843Smckusick 
37857843Smckusick /*
37957843Smckusick  * Validate parameters and get old / set new parameters
38057843Smckusick  * for a string-valued sysctl function.
38157843Smckusick  */
38257843Smckusick sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
38357843Smckusick 	void *oldp;
38458466Sbostic 	size_t *oldlenp;
38557843Smckusick 	void *newp;
38658466Sbostic 	size_t newlen;
38757843Smckusick 	char *str;
38857843Smckusick 	int maxlen;
38957843Smckusick {
39057843Smckusick 	int len, error = 0;
39157843Smckusick 
39257843Smckusick 	len = strlen(str) + 1;
39357843Smckusick 	if (oldp && *oldlenp < len)
39457843Smckusick 		return (ENOMEM);
39557843Smckusick 	if (newp && newlen >= maxlen)
39657843Smckusick 		return (EINVAL);
39758128Sralph 	if (oldp) {
39858128Sralph 		*oldlenp = len;
39957843Smckusick 		error = copyout(str, oldp, len);
40058128Sralph 	}
40157843Smckusick 	if (error == 0 && newp) {
40257843Smckusick 		error = copyin(newp, str, newlen);
40357843Smckusick 		str[newlen] = 0;
40457843Smckusick 	}
40557843Smckusick 	return (error);
40657843Smckusick }
40757843Smckusick 
40857843Smckusick /*
40957843Smckusick  * As above, but read-only.
41057843Smckusick  */
41157843Smckusick sysctl_rdstring(oldp, oldlenp, newp, str)
41257843Smckusick 	void *oldp;
41358466Sbostic 	size_t *oldlenp;
41457843Smckusick 	void *newp;
41557843Smckusick 	char *str;
41657843Smckusick {
41757843Smckusick 	int len, error = 0;
41857843Smckusick 
41957843Smckusick 	len = strlen(str) + 1;
42057843Smckusick 	if (oldp && *oldlenp < len)
42157843Smckusick 		return (ENOMEM);
42257843Smckusick 	if (newp)
42357843Smckusick 		return (EPERM);
42457843Smckusick 	*oldlenp = len;
42557843Smckusick 	if (oldp)
42657843Smckusick 		error = copyout(str, oldp, len);
42757843Smckusick 	return (error);
42857843Smckusick }
42957843Smckusick 
43057843Smckusick /*
43159312Smckusick  * Validate parameters and get old / set new parameters
43259312Smckusick  * for a structure oriented sysctl function.
43359312Smckusick  */
43459312Smckusick sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
43559312Smckusick 	void *oldp;
43659312Smckusick 	size_t *oldlenp;
43759312Smckusick 	void *newp;
43859312Smckusick 	size_t newlen;
43959312Smckusick 	void *sp;
44059312Smckusick 	int len;
44159312Smckusick {
44259312Smckusick 	int error = 0;
44359312Smckusick 
44459312Smckusick 	if (oldp && *oldlenp < len)
44559312Smckusick 		return (ENOMEM);
44659312Smckusick 	if (newp && newlen > len)
44759312Smckusick 		return (EINVAL);
44859312Smckusick 	if (oldp) {
44959312Smckusick 		*oldlenp = len;
45059312Smckusick 		error = copyout(sp, oldp, len);
45159312Smckusick 	}
45259312Smckusick 	if (error == 0 && newp)
45359312Smckusick 		error = copyin(newp, sp, len);
45459312Smckusick 	return (error);
45559312Smckusick }
45659312Smckusick 
45759312Smckusick /*
45857843Smckusick  * Validate parameters and get old parameters
45957843Smckusick  * for a structure oriented sysctl function.
46057843Smckusick  */
46157843Smckusick sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
46257843Smckusick 	void *oldp;
46358466Sbostic 	size_t *oldlenp;
46458466Sbostic 	void *newp, *sp;
46557843Smckusick 	int len;
46657843Smckusick {
46757843Smckusick 	int error = 0;
46857843Smckusick 
46957843Smckusick 	if (oldp && *oldlenp < len)
47057843Smckusick 		return (ENOMEM);
47157843Smckusick 	if (newp)
47257843Smckusick 		return (EPERM);
47357843Smckusick 	*oldlenp = len;
47457843Smckusick 	if (oldp)
47557843Smckusick 		error = copyout(sp, oldp, len);
47657843Smckusick 	return (error);
47757843Smckusick }
47857843Smckusick 
47957843Smckusick /*
48057843Smckusick  * Get file structures.
48157843Smckusick  */
48257843Smckusick sysctl_file(where, sizep)
48357843Smckusick 	char *where;
48458466Sbostic 	size_t *sizep;
48557843Smckusick {
48657843Smckusick 	int buflen, error;
48757843Smckusick 	struct file *fp;
48857843Smckusick 	char *start = where;
48957843Smckusick 
49057843Smckusick 	buflen = *sizep;
49157843Smckusick 	if (where == NULL) {
49257843Smckusick 		/*
49357843Smckusick 		 * overestimate by 10 files
49457843Smckusick 		 */
49557843Smckusick 		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
49657843Smckusick 		return (0);
49757843Smckusick 	}
49857843Smckusick 
49957843Smckusick 	/*
50057843Smckusick 	 * first copyout filehead
50157843Smckusick 	 */
50257843Smckusick 	if (buflen < sizeof(filehead)) {
50357843Smckusick 		*sizep = 0;
50457843Smckusick 		return (0);
50557843Smckusick 	}
50657843Smckusick 	if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
50757843Smckusick 		return (error);
50866789Smckusick 	buflen -= sizeof(filehead);
50957843Smckusick 	where += sizeof(filehead);
51057843Smckusick 
51157843Smckusick 	/*
51257843Smckusick 	 * followed by an array of file structures
51357843Smckusick 	 */
51467732Smckusick 	for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
51557843Smckusick 		if (buflen < sizeof(struct file)) {
51657843Smckusick 			*sizep = where - start;
51757843Smckusick 			return (ENOMEM);
51857843Smckusick 		}
51957843Smckusick 		if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
52057843Smckusick 			return (error);
52157843Smckusick 		buflen -= sizeof(struct file);
52257843Smckusick 		where += sizeof(struct file);
52357843Smckusick 	}
52457843Smckusick 	*sizep = where - start;
52557843Smckusick 	return (0);
52657843Smckusick }
52757843Smckusick 
52859312Smckusick /*
52959312Smckusick  * try over estimating by 5 procs
53039963Smarc  */
53157843Smckusick #define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
53239963Smarc 
53357843Smckusick sysctl_doproc(name, namelen, where, sizep)
53457843Smckusick 	int *name;
53558466Sbostic 	u_int namelen;
53639963Smarc 	char *where;
53758466Sbostic 	size_t *sizep;
53839963Smarc {
53939963Smarc 	register struct proc *p;
54043419Smarc 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
54157843Smckusick 	register int needed = 0;
54257843Smckusick 	int buflen = where != NULL ? *sizep : 0;
54339963Smarc 	int doingzomb;
54440067Smarc 	struct eproc eproc;
54539963Smarc 	int error = 0;
54639963Smarc 
54759977Smckusick 	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
54857843Smckusick 		return (EINVAL);
54967732Smckusick 	p = allproc.lh_first;
55039963Smarc 	doingzomb = 0;
55139963Smarc again:
55267732Smckusick 	for (; p != 0; p = p->p_list.le_next) {
55353819Smckusick 		/*
55453819Smckusick 		 * Skip embryonic processes.
55553819Smckusick 		 */
55653819Smckusick 		if (p->p_stat == SIDL)
55753819Smckusick 			continue;
55859312Smckusick 		/*
55939963Smarc 		 * TODO - make more efficient (see notes below).
56059312Smckusick 		 * do by session.
56139963Smarc 		 */
56257843Smckusick 		switch (name[0]) {
56339963Smarc 
56457843Smckusick 		case KERN_PROC_PID:
56539963Smarc 			/* could do this with just a lookup */
56657843Smckusick 			if (p->p_pid != (pid_t)name[1])
56739963Smarc 				continue;
56839963Smarc 			break;
56939963Smarc 
57057843Smckusick 		case KERN_PROC_PGRP:
57139963Smarc 			/* could do this by traversing pgrp */
57257843Smckusick 			if (p->p_pgrp->pg_id != (pid_t)name[1])
57339963Smarc 				continue;
57439963Smarc 			break;
57539963Smarc 
57657843Smckusick 		case KERN_PROC_TTY:
57764573Sbostic 			if ((p->p_flag & P_CONTROLT) == 0 ||
57839963Smarc 			    p->p_session->s_ttyp == NULL ||
57957843Smckusick 			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
58039963Smarc 				continue;
58139963Smarc 			break;
58239963Smarc 
58357843Smckusick 		case KERN_PROC_UID:
58457843Smckusick 			if (p->p_ucred->cr_uid != (uid_t)name[1])
58539963Smarc 				continue;
58639963Smarc 			break;
58739963Smarc 
58857843Smckusick 		case KERN_PROC_RUID:
58957843Smckusick 			if (p->p_cred->p_ruid != (uid_t)name[1])
59039963Smarc 				continue;
59139963Smarc 			break;
59239963Smarc 		}
59357843Smckusick 		if (buflen >= sizeof(struct kinfo_proc)) {
59448407Skarels 			fill_eproc(p, &eproc);
59559312Smckusick 			if (error = copyout((caddr_t)p, &dp->kp_proc,
59657843Smckusick 			    sizeof(struct proc)))
59739963Smarc 				return (error);
59859312Smckusick 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
59957843Smckusick 			    sizeof(eproc)))
60039963Smarc 				return (error);
60143419Smarc 			dp++;
60257843Smckusick 			buflen -= sizeof(struct kinfo_proc);
60339963Smarc 		}
60457843Smckusick 		needed += sizeof(struct kinfo_proc);
60539963Smarc 	}
60639963Smarc 	if (doingzomb == 0) {
60767732Smckusick 		p = zombproc.lh_first;
60839963Smarc 		doingzomb++;
60939963Smarc 		goto again;
61039963Smarc 	}
61157843Smckusick 	if (where != NULL) {
61257843Smckusick 		*sizep = (caddr_t)dp - where;
61357843Smckusick 		if (needed > *sizep)
61457843Smckusick 			return (ENOMEM);
61557843Smckusick 	} else {
61657843Smckusick 		needed += KERN_PROCSLOP;
61757843Smckusick 		*sizep = needed;
61857843Smckusick 	}
61939963Smarc 	return (0);
62039963Smarc }
62148407Skarels 
62248407Skarels /*
62348407Skarels  * Fill in an eproc structure for the specified process.
62448407Skarels  */
62548407Skarels void
62648407Skarels fill_eproc(p, ep)
62748407Skarels 	register struct proc *p;
62848407Skarels 	register struct eproc *ep;
62948407Skarels {
63048407Skarels 	register struct tty *tp;
63148407Skarels 
63248407Skarels 	ep->e_paddr = p;
63348407Skarels 	ep->e_sess = p->p_pgrp->pg_session;
63448407Skarels 	ep->e_pcred = *p->p_cred;
63548407Skarels 	ep->e_ucred = *p->p_ucred;
63652405Storek 	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
63752405Storek 		ep->e_vm.vm_rssize = 0;
63852405Storek 		ep->e_vm.vm_tsize = 0;
63952405Storek 		ep->e_vm.vm_dsize = 0;
64052405Storek 		ep->e_vm.vm_ssize = 0;
64152405Storek #ifndef sparc
64252405Storek 		/* ep->e_vm.vm_pmap = XXX; */
64352405Storek #endif
64452405Storek 	} else {
64552405Storek 		register struct vmspace *vm = p->p_vmspace;
64652405Storek 
64765548Smckusick #ifdef pmap_resident_count
64865548Smckusick 		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
64965548Smckusick #else
65052405Storek 		ep->e_vm.vm_rssize = vm->vm_rssize;
65165548Smckusick #endif
65252405Storek 		ep->e_vm.vm_tsize = vm->vm_tsize;
65352405Storek 		ep->e_vm.vm_dsize = vm->vm_dsize;
65452405Storek 		ep->e_vm.vm_ssize = vm->vm_ssize;
65552405Storek #ifndef sparc
65652405Storek 		ep->e_vm.vm_pmap = vm->vm_pmap;
65752405Storek #endif
65852405Storek 	}
65949141Skarels 	if (p->p_pptr)
66049141Skarels 		ep->e_ppid = p->p_pptr->p_pid;
66149141Skarels 	else
66249141Skarels 		ep->e_ppid = 0;
66348407Skarels 	ep->e_pgid = p->p_pgrp->pg_id;
66448407Skarels 	ep->e_jobc = p->p_pgrp->pg_jobc;
66564573Sbostic 	if ((p->p_flag & P_CONTROLT) &&
66648407Skarels 	     (tp = ep->e_sess->s_ttyp)) {
66748407Skarels 		ep->e_tdev = tp->t_dev;
66850022Skarels 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
66948407Skarels 		ep->e_tsess = tp->t_session;
67048407Skarels 	} else
67148407Skarels 		ep->e_tdev = NODEV;
67248407Skarels 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
67348407Skarels 	if (SESS_LEADER(p))
67448407Skarels 		ep->e_flag |= EPROC_SLEADER;
67548407Skarels 	if (p->p_wmesg)
67648407Skarels 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
67748407Skarels 	ep->e_xsize = ep->e_xrssize = 0;
67848407Skarels 	ep->e_xccount = ep->e_xswrss = 0;
67948407Skarels }
68050149Smarc 
68157843Smckusick #ifdef COMPAT_43
68257843Smckusick #include <sys/socket.h>
68357906Smckusick #define	KINFO_PROC		(0<<8)
68457906Smckusick #define	KINFO_RT		(1<<8)
68557906Smckusick #define	KINFO_VNODE		(2<<8)
68657906Smckusick #define	KINFO_FILE		(3<<8)
68757906Smckusick #define	KINFO_METER		(4<<8)
68857906Smckusick #define	KINFO_LOADAVG		(5<<8)
68957906Smckusick #define	KINFO_CLOCKRATE		(6<<8)
69057843Smckusick 
691*68298Scgd compat_43_getkerninfo(p, uap, retval)
69257843Smckusick 	struct proc *p;
693*68298Scgd 	register struct compat_43_getkerninfo_args /* {
694*68298Scgd 		syscallarg(int) op;
695*68298Scgd 		syscallarg(char *) where;
696*68298Scgd 		syscallarg(int *) size;
697*68298Scgd 		syscallarg(int) arg;
698*68298Scgd 	} */ *uap;
699*68298Scgd 	register_t *retval;
70050149Smarc {
70157843Smckusick 	int error, name[5];
702*68298Scgd 	size_t size;
70350149Smarc 
704*68298Scgd 	if (SCARG(uap, size) && (error = copyin((caddr_t)SCARG(uap, size),
705*68298Scgd 	    (caddr_t)&size, sizeof(size))))
70657843Smckusick 		return (error);
70750149Smarc 
708*68298Scgd 	switch (SCARG(uap, op) & 0xff00) {
70950149Smarc 
71057843Smckusick 	case KINFO_RT:
71157843Smckusick 		name[0] = PF_ROUTE;
71257843Smckusick 		name[1] = 0;
713*68298Scgd 		name[2] = (SCARG(uap, op) & 0xff0000) >> 16;
714*68298Scgd 		name[3] = SCARG(uap, op) & 0xff;
715*68298Scgd 		name[4] = SCARG(uap, arg);
716*68298Scgd 		error =
717*68298Scgd 		    net_sysctl(name, 5, SCARG(uap, where), &size, NULL, 0, p);
71857843Smckusick 		break;
71957843Smckusick 
72057843Smckusick 	case KINFO_VNODE:
72157843Smckusick 		name[0] = KERN_VNODE;
722*68298Scgd 		error =
723*68298Scgd 		    kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
72457843Smckusick 		break;
72557843Smckusick 
72657843Smckusick 	case KINFO_PROC:
72757843Smckusick 		name[0] = KERN_PROC;
728*68298Scgd 		name[1] = SCARG(uap, op) & 0xff;
729*68298Scgd 		name[2] = SCARG(uap, arg);
730*68298Scgd 		error =
731*68298Scgd 		    kern_sysctl(name, 3, SCARG(uap, where), &size, NULL, 0, p);
73257843Smckusick 		break;
73357843Smckusick 
73457843Smckusick 	case KINFO_FILE:
73557843Smckusick 		name[0] = KERN_FILE;
736*68298Scgd 		error =
737*68298Scgd 		    kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
73857843Smckusick 		break;
73957843Smckusick 
74057843Smckusick 	case KINFO_METER:
74157843Smckusick 		name[0] = VM_METER;
742*68298Scgd 		error =
743*68298Scgd 		    vm_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
74457843Smckusick 		break;
74557843Smckusick 
74657843Smckusick 	case KINFO_LOADAVG:
74757843Smckusick 		name[0] = VM_LOADAVG;
748*68298Scgd 		error =
749*68298Scgd 		    vm_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
75057843Smckusick 		break;
75157843Smckusick 
75257843Smckusick 	case KINFO_CLOCKRATE:
75357843Smckusick 		name[0] = KERN_CLOCKRATE;
754*68298Scgd 		error =
755*68298Scgd 		    kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
75657843Smckusick 		break;
75757843Smckusick 
75857843Smckusick 	default:
75958415Smckusick 		return (EOPNOTSUPP);
76050149Smarc 	}
76157843Smckusick 	if (error)
76257843Smckusick 		return (error);
76357843Smckusick 	*retval = size;
764*68298Scgd 	if (SCARG(uap, size))
765*68298Scgd 		error = copyout((caddr_t)&size, (caddr_t)SCARG(uap, size),
76658461Smckusick 		    sizeof(size));
76758461Smckusick 	return (error);
76850149Smarc }
76957843Smckusick #endif /* COMPAT_43 */
770