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*69575Smckusick * @(#)kern_sysctl.c 8.9 (Berkeley) 05/20/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
3168298Scgd #include <sys/mount.h>
3268298Scgd #include <sys/syscallargs.h>
3368298Scgd
3457843Smckusick sysctlfn kern_sysctl;
3557843Smckusick sysctlfn hw_sysctl;
3659161Smckusick #ifdef DEBUG
3759161Smckusick sysctlfn debug_sysctl;
3859161Smckusick #endif
3957843Smckusick extern sysctlfn vm_sysctl;
4068657Smckusick extern sysctlfn vfs_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
__sysctl(p,uap,retval)5459718Sbostic __sysctl(p, uap, retval)
5543444Smckusick struct proc *p;
5668298Scgd register struct __sysctl_args /* {
5768298Scgd syscallarg(int *) name;
5868298Scgd syscallarg(u_int) namelen;
5968298Scgd syscallarg(void *) old;
6068298Scgd syscallarg(size_t *) oldlenp;
6168298Scgd syscallarg(void *) new;
6268298Scgd syscallarg(size_t) newlen;
6368298Scgd } */ *uap;
6468298Scgd register_t *retval;
6543444Smckusick {
6657843Smckusick int error, dolock = 1;
6768298Scgd size_t savelen, oldlen = 0;
6857843Smckusick sysctlfn *fn;
6957843Smckusick int name[CTL_MAXNAME];
7039963Smarc
7168298Scgd if (SCARG(uap, new) != NULL &&
7268298Scgd (error = suser(p->p_ucred, &p->p_acflag)))
7357843Smckusick return (error);
7457843Smckusick /*
7557843Smckusick * all top-level sysctl names are non-terminal
7657843Smckusick */
7768298Scgd if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2)
7857843Smckusick return (EINVAL);
7968298Scgd if (error =
8068298Scgd 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;
9868657Smckusick case CTL_VFS:
9968657Smckusick fn = vfs_sysctl;
10050909Smckusick break;
10157843Smckusick case CTL_MACHDEP:
10257843Smckusick fn = cpu_sysctl;
10352669Smckusick break;
10459161Smckusick #ifdef DEBUG
10559161Smckusick case CTL_DEBUG:
10659161Smckusick fn = debug_sysctl;
10759161Smckusick break;
10859161Smckusick #endif
10939963Smarc default:
11057843Smckusick return (EOPNOTSUPP);
11139963Smarc }
11257843Smckusick
11368298Scgd if (SCARG(uap, oldlenp) &&
11468298Scgd (error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen))))
11557843Smckusick return (error);
11668298Scgd if (SCARG(uap, old) != NULL) {
11768298Scgd if (!useracc(SCARG(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)
12668298Scgd vslock(SCARG(uap, old), oldlen);
12757843Smckusick savelen = oldlen;
12840813Smarc }
12968298Scgd error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old),
13068298Scgd &oldlen, SCARG(uap, new), SCARG(uap, newlen), p);
13168298Scgd if (SCARG(uap, old) != NULL) {
13257843Smckusick if (dolock)
13368298Scgd vsunlock(SCARG(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);
14268298Scgd if (SCARG(uap, oldlenp))
14368298Scgd error = copyout(&oldlen, SCARG(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 */
kern_sysctl(name,namelen,oldp,oldlenp,newp,newlen,p)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 {
16863456Smckusick int error, level, inthostid;
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));
18459718Sbostic case KERN_MAXVNODES:
18559718Sbostic return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
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));
19057843Smckusick case KERN_ARGMAX:
19157843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
19258415Smckusick case KERN_SECURELVL:
19358415Smckusick level = securelevel;
19458415Smckusick if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
19558415Smckusick newp == NULL)
19658415Smckusick return (error);
19758415Smckusick if (level < securelevel && p->p_pid != 1)
19858415Smckusick return (EPERM);
19958415Smckusick securelevel = level;
20058415Smckusick return (0);
20159718Sbostic case KERN_HOSTNAME:
20259718Sbostic error = sysctl_string(oldp, oldlenp, newp, newlen,
20359718Sbostic hostname, sizeof(hostname));
20461302Smckusick if (newp && !error)
20559718Sbostic hostnamelen = newlen;
20659718Sbostic return (error);
20759718Sbostic case KERN_HOSTID:
20863456Smckusick inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */
20963456Smckusick error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
21063456Smckusick hostid = inthostid;
21163456Smckusick return (error);
21257843Smckusick case KERN_CLOCKRATE:
21357843Smckusick return (sysctl_clockrate(oldp, oldlenp));
21460153Smckusick case KERN_BOOTTIME:
21560153Smckusick return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
21660153Smckusick sizeof(struct timeval)));
21757843Smckusick case KERN_VNODE:
218*69575Smckusick return (sysctl_vnode(oldp, oldlenp, p));
21957843Smckusick case KERN_PROC:
22057843Smckusick return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
22159718Sbostic case KERN_FILE:
22259718Sbostic return (sysctl_file(oldp, oldlenp));
22359312Smckusick #ifdef GPROF
22459312Smckusick case KERN_PROF:
22559312Smckusick return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
22659312Smckusick newp, newlen));
22759312Smckusick #endif
22859718Sbostic case KERN_POSIX1:
22959718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
23059718Sbostic case KERN_NGROUPS:
23159718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
23259718Sbostic case KERN_JOB_CONTROL:
23359718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, 1));
23459718Sbostic case KERN_SAVED_IDS:
23559718Sbostic #ifdef _POSIX_SAVED_IDS
23659718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, 1));
23759718Sbostic #else
23859718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, 0));
23959718Sbostic #endif
24057843Smckusick default:
24157843Smckusick return (EOPNOTSUPP);
24252405Storek }
24357843Smckusick /* NOTREACHED */
24457843Smckusick }
24557843Smckusick
24658415Smckusick /*
24758415Smckusick * hardware related system variables.
24858415Smckusick */
hw_sysctl(name,namelen,oldp,oldlenp,newp,newlen,p)24958415Smckusick hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
25057843Smckusick int *name;
25157843Smckusick u_int namelen;
25257843Smckusick void *oldp;
25358466Sbostic size_t *oldlenp;
25457843Smckusick void *newp;
25558466Sbostic size_t newlen;
25658415Smckusick struct proc *p;
25757843Smckusick {
25857843Smckusick extern char machine[], cpu_model[];
25957843Smckusick
26057843Smckusick /* all sysctl names at this level are terminal */
26157843Smckusick if (namelen != 1)
26257843Smckusick return (ENOTDIR); /* overloaded */
26357843Smckusick
26457843Smckusick switch (name[0]) {
26557843Smckusick case HW_MACHINE:
26657843Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, machine));
26757843Smckusick case HW_MODEL:
26857843Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
26957843Smckusick case HW_NCPU:
27057843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */
27159618Smckusick case HW_BYTEORDER:
27259618Smckusick return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
27357843Smckusick case HW_PHYSMEM:
27457843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
27557843Smckusick case HW_USERMEM:
27657843Smckusick return (sysctl_rdint(oldp, oldlenp, newp,
27757843Smckusick ctob(physmem - cnt.v_wire_count)));
27857843Smckusick case HW_PAGESIZE:
27957843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
28057843Smckusick default:
28157843Smckusick return (EOPNOTSUPP);
28257843Smckusick }
28357843Smckusick /* NOTREACHED */
28457843Smckusick }
28557843Smckusick
28659161Smckusick #ifdef DEBUG
28757843Smckusick /*
28859161Smckusick * Debugging related system variables.
28959161Smckusick */
29059161Smckusick struct ctldebug debug0, debug1, debug2, debug3, debug4;
29159161Smckusick struct ctldebug debug5, debug6, debug7, debug8, debug9;
29259161Smckusick struct ctldebug debug10, debug11, debug12, debug13, debug14;
29359161Smckusick struct ctldebug debug15, debug16, debug17, debug18, debug19;
29459161Smckusick static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
29559161Smckusick &debug0, &debug1, &debug2, &debug3, &debug4,
29659161Smckusick &debug5, &debug6, &debug7, &debug8, &debug9,
29759161Smckusick &debug10, &debug11, &debug12, &debug13, &debug14,
29859161Smckusick &debug15, &debug16, &debug17, &debug18, &debug19,
29959161Smckusick };
30059161Smckusick int
debug_sysctl(name,namelen,oldp,oldlenp,newp,newlen,p)30159161Smckusick debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
30259161Smckusick int *name;
30359161Smckusick u_int namelen;
30459161Smckusick void *oldp;
30559161Smckusick size_t *oldlenp;
30659161Smckusick void *newp;
30759161Smckusick size_t newlen;
30859161Smckusick struct proc *p;
30959161Smckusick {
31059161Smckusick struct ctldebug *cdp;
31159161Smckusick
31259161Smckusick /* all sysctl names at this level are name and field */
31359161Smckusick if (namelen != 2)
31459161Smckusick return (ENOTDIR); /* overloaded */
31559161Smckusick cdp = debugvars[name[0]];
31668657Smckusick if (name[0] >= CTL_DEBUG_MAXID || cdp->debugname == 0)
31759161Smckusick return (EOPNOTSUPP);
31859161Smckusick switch (name[1]) {
31959161Smckusick case CTL_DEBUG_NAME:
32059161Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
32159161Smckusick case CTL_DEBUG_VALUE:
32259161Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
32359161Smckusick default:
32459161Smckusick return (EOPNOTSUPP);
32559161Smckusick }
32659161Smckusick /* NOTREACHED */
32759161Smckusick }
32859161Smckusick #endif /* DEBUG */
32959161Smckusick
33059161Smckusick /*
33157843Smckusick * Validate parameters and get old / set new parameters
33257843Smckusick * for an integer-valued sysctl function.
33357843Smckusick */
sysctl_int(oldp,oldlenp,newp,newlen,valp)33457843Smckusick sysctl_int(oldp, oldlenp, newp, newlen, valp)
33557843Smckusick void *oldp;
33658466Sbostic size_t *oldlenp;
33757843Smckusick void *newp;
33858466Sbostic size_t newlen;
33957843Smckusick int *valp;
34057843Smckusick {
34157843Smckusick int error = 0;
34257843Smckusick
34357843Smckusick if (oldp && *oldlenp < sizeof(int))
34457843Smckusick return (ENOMEM);
34557843Smckusick if (newp && newlen != sizeof(int))
34657843Smckusick return (EINVAL);
34757843Smckusick *oldlenp = sizeof(int);
34857843Smckusick if (oldp)
34957843Smckusick error = copyout(valp, oldp, sizeof(int));
35057843Smckusick if (error == 0 && newp)
35157843Smckusick error = copyin(newp, valp, sizeof(int));
35243444Smckusick return (error);
35339963Smarc }
35439963Smarc
35557843Smckusick /*
35657843Smckusick * As above, but read-only.
35757843Smckusick */
sysctl_rdint(oldp,oldlenp,newp,val)35857843Smckusick sysctl_rdint(oldp, oldlenp, newp, val)
35957843Smckusick void *oldp;
36058466Sbostic size_t *oldlenp;
36157843Smckusick void *newp;
36257843Smckusick int val;
36357843Smckusick {
36457843Smckusick int error = 0;
36557843Smckusick
36657843Smckusick if (oldp && *oldlenp < sizeof(int))
36757843Smckusick return (ENOMEM);
36857843Smckusick if (newp)
36957843Smckusick return (EPERM);
37057843Smckusick *oldlenp = sizeof(int);
37157843Smckusick if (oldp)
37257843Smckusick error = copyout((caddr_t)&val, oldp, sizeof(int));
37357843Smckusick return (error);
37457843Smckusick }
37557843Smckusick
37657843Smckusick /*
37757843Smckusick * Validate parameters and get old / set new parameters
37857843Smckusick * for a string-valued sysctl function.
37957843Smckusick */
sysctl_string(oldp,oldlenp,newp,newlen,str,maxlen)38057843Smckusick sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
38157843Smckusick void *oldp;
38258466Sbostic size_t *oldlenp;
38357843Smckusick void *newp;
38458466Sbostic size_t newlen;
38557843Smckusick char *str;
38657843Smckusick int maxlen;
38757843Smckusick {
38857843Smckusick int len, error = 0;
38957843Smckusick
39057843Smckusick len = strlen(str) + 1;
39157843Smckusick if (oldp && *oldlenp < len)
39257843Smckusick return (ENOMEM);
39357843Smckusick if (newp && newlen >= maxlen)
39457843Smckusick return (EINVAL);
39558128Sralph if (oldp) {
39658128Sralph *oldlenp = len;
39757843Smckusick error = copyout(str, oldp, len);
39858128Sralph }
39957843Smckusick if (error == 0 && newp) {
40057843Smckusick error = copyin(newp, str, newlen);
40157843Smckusick str[newlen] = 0;
40257843Smckusick }
40357843Smckusick return (error);
40457843Smckusick }
40557843Smckusick
40657843Smckusick /*
40757843Smckusick * As above, but read-only.
40857843Smckusick */
sysctl_rdstring(oldp,oldlenp,newp,str)40957843Smckusick sysctl_rdstring(oldp, oldlenp, newp, str)
41057843Smckusick void *oldp;
41158466Sbostic size_t *oldlenp;
41257843Smckusick void *newp;
41357843Smckusick char *str;
41457843Smckusick {
41557843Smckusick int len, error = 0;
41657843Smckusick
41757843Smckusick len = strlen(str) + 1;
41857843Smckusick if (oldp && *oldlenp < len)
41957843Smckusick return (ENOMEM);
42057843Smckusick if (newp)
42157843Smckusick return (EPERM);
42257843Smckusick *oldlenp = len;
42357843Smckusick if (oldp)
42457843Smckusick error = copyout(str, oldp, len);
42557843Smckusick return (error);
42657843Smckusick }
42757843Smckusick
42857843Smckusick /*
42959312Smckusick * Validate parameters and get old / set new parameters
43059312Smckusick * for a structure oriented sysctl function.
43159312Smckusick */
sysctl_struct(oldp,oldlenp,newp,newlen,sp,len)43259312Smckusick sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
43359312Smckusick void *oldp;
43459312Smckusick size_t *oldlenp;
43559312Smckusick void *newp;
43659312Smckusick size_t newlen;
43759312Smckusick void *sp;
43859312Smckusick int len;
43959312Smckusick {
44059312Smckusick int error = 0;
44159312Smckusick
44259312Smckusick if (oldp && *oldlenp < len)
44359312Smckusick return (ENOMEM);
44459312Smckusick if (newp && newlen > len)
44559312Smckusick return (EINVAL);
44659312Smckusick if (oldp) {
44759312Smckusick *oldlenp = len;
44859312Smckusick error = copyout(sp, oldp, len);
44959312Smckusick }
45059312Smckusick if (error == 0 && newp)
45159312Smckusick error = copyin(newp, sp, len);
45259312Smckusick return (error);
45359312Smckusick }
45459312Smckusick
45559312Smckusick /*
45657843Smckusick * Validate parameters and get old parameters
45757843Smckusick * for a structure oriented sysctl function.
45857843Smckusick */
sysctl_rdstruct(oldp,oldlenp,newp,sp,len)45957843Smckusick sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
46057843Smckusick void *oldp;
46158466Sbostic size_t *oldlenp;
46258466Sbostic void *newp, *sp;
46357843Smckusick int len;
46457843Smckusick {
46557843Smckusick int error = 0;
46657843Smckusick
46757843Smckusick if (oldp && *oldlenp < len)
46857843Smckusick return (ENOMEM);
46957843Smckusick if (newp)
47057843Smckusick return (EPERM);
47157843Smckusick *oldlenp = len;
47257843Smckusick if (oldp)
47357843Smckusick error = copyout(sp, oldp, len);
47457843Smckusick return (error);
47557843Smckusick }
47657843Smckusick
47757843Smckusick /*
47857843Smckusick * Get file structures.
47957843Smckusick */
sysctl_file(where,sizep)48057843Smckusick sysctl_file(where, sizep)
48157843Smckusick char *where;
48258466Sbostic size_t *sizep;
48357843Smckusick {
48457843Smckusick int buflen, error;
48557843Smckusick struct file *fp;
48657843Smckusick char *start = where;
48757843Smckusick
48857843Smckusick buflen = *sizep;
48957843Smckusick if (where == NULL) {
49057843Smckusick /*
49157843Smckusick * overestimate by 10 files
49257843Smckusick */
49357843Smckusick *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
49457843Smckusick return (0);
49557843Smckusick }
49657843Smckusick
49757843Smckusick /*
49857843Smckusick * first copyout filehead
49957843Smckusick */
50057843Smckusick if (buflen < sizeof(filehead)) {
50157843Smckusick *sizep = 0;
50257843Smckusick return (0);
50357843Smckusick }
50457843Smckusick if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
50557843Smckusick return (error);
50666789Smckusick buflen -= sizeof(filehead);
50757843Smckusick where += sizeof(filehead);
50857843Smckusick
50957843Smckusick /*
51057843Smckusick * followed by an array of file structures
51157843Smckusick */
51267732Smckusick for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
51357843Smckusick if (buflen < sizeof(struct file)) {
51457843Smckusick *sizep = where - start;
51557843Smckusick return (ENOMEM);
51657843Smckusick }
51757843Smckusick if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
51857843Smckusick return (error);
51957843Smckusick buflen -= sizeof(struct file);
52057843Smckusick where += sizeof(struct file);
52157843Smckusick }
52257843Smckusick *sizep = where - start;
52357843Smckusick return (0);
52457843Smckusick }
52557843Smckusick
52659312Smckusick /*
52759312Smckusick * try over estimating by 5 procs
52839963Smarc */
52957843Smckusick #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
53039963Smarc
sysctl_doproc(name,namelen,where,sizep)53157843Smckusick sysctl_doproc(name, namelen, where, sizep)
53257843Smckusick int *name;
53358466Sbostic u_int namelen;
53439963Smarc char *where;
53558466Sbostic size_t *sizep;
53639963Smarc {
53739963Smarc register struct proc *p;
53843419Smarc register struct kinfo_proc *dp = (struct kinfo_proc *)where;
53957843Smckusick register int needed = 0;
54057843Smckusick int buflen = where != NULL ? *sizep : 0;
54139963Smarc int doingzomb;
54240067Smarc struct eproc eproc;
54339963Smarc int error = 0;
54439963Smarc
54559977Smckusick if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
54657843Smckusick return (EINVAL);
54767732Smckusick p = allproc.lh_first;
54839963Smarc doingzomb = 0;
54939963Smarc again:
55067732Smckusick for (; p != 0; p = p->p_list.le_next) {
55153819Smckusick /*
55253819Smckusick * Skip embryonic processes.
55353819Smckusick */
55453819Smckusick if (p->p_stat == SIDL)
55553819Smckusick continue;
55659312Smckusick /*
55739963Smarc * TODO - make more efficient (see notes below).
55859312Smckusick * do by session.
55939963Smarc */
56057843Smckusick switch (name[0]) {
56139963Smarc
56257843Smckusick case KERN_PROC_PID:
56339963Smarc /* could do this with just a lookup */
56457843Smckusick if (p->p_pid != (pid_t)name[1])
56539963Smarc continue;
56639963Smarc break;
56739963Smarc
56857843Smckusick case KERN_PROC_PGRP:
56939963Smarc /* could do this by traversing pgrp */
57057843Smckusick if (p->p_pgrp->pg_id != (pid_t)name[1])
57139963Smarc continue;
57239963Smarc break;
57339963Smarc
57457843Smckusick case KERN_PROC_TTY:
57564573Sbostic if ((p->p_flag & P_CONTROLT) == 0 ||
57639963Smarc p->p_session->s_ttyp == NULL ||
57757843Smckusick p->p_session->s_ttyp->t_dev != (dev_t)name[1])
57839963Smarc continue;
57939963Smarc break;
58039963Smarc
58157843Smckusick case KERN_PROC_UID:
58257843Smckusick if (p->p_ucred->cr_uid != (uid_t)name[1])
58339963Smarc continue;
58439963Smarc break;
58539963Smarc
58657843Smckusick case KERN_PROC_RUID:
58757843Smckusick if (p->p_cred->p_ruid != (uid_t)name[1])
58839963Smarc continue;
58939963Smarc break;
59039963Smarc }
59157843Smckusick if (buflen >= sizeof(struct kinfo_proc)) {
59248407Skarels fill_eproc(p, &eproc);
59359312Smckusick if (error = copyout((caddr_t)p, &dp->kp_proc,
59457843Smckusick sizeof(struct proc)))
59539963Smarc return (error);
59659312Smckusick if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
59757843Smckusick sizeof(eproc)))
59839963Smarc return (error);
59943419Smarc dp++;
60057843Smckusick buflen -= sizeof(struct kinfo_proc);
60139963Smarc }
60257843Smckusick needed += sizeof(struct kinfo_proc);
60339963Smarc }
60439963Smarc if (doingzomb == 0) {
60567732Smckusick p = zombproc.lh_first;
60639963Smarc doingzomb++;
60739963Smarc goto again;
60839963Smarc }
60957843Smckusick if (where != NULL) {
61057843Smckusick *sizep = (caddr_t)dp - where;
61157843Smckusick if (needed > *sizep)
61257843Smckusick return (ENOMEM);
61357843Smckusick } else {
61457843Smckusick needed += KERN_PROCSLOP;
61557843Smckusick *sizep = needed;
61657843Smckusick }
61739963Smarc return (0);
61839963Smarc }
61948407Skarels
62048407Skarels /*
62148407Skarels * Fill in an eproc structure for the specified process.
62248407Skarels */
62348407Skarels void
fill_eproc(p,ep)62448407Skarels fill_eproc(p, ep)
62548407Skarels register struct proc *p;
62648407Skarels register struct eproc *ep;
62748407Skarels {
62848407Skarels register struct tty *tp;
62948407Skarels
63048407Skarels ep->e_paddr = p;
63148407Skarels ep->e_sess = p->p_pgrp->pg_session;
63248407Skarels ep->e_pcred = *p->p_cred;
63348407Skarels ep->e_ucred = *p->p_ucred;
63452405Storek if (p->p_stat == SIDL || p->p_stat == SZOMB) {
63552405Storek ep->e_vm.vm_rssize = 0;
63652405Storek ep->e_vm.vm_tsize = 0;
63752405Storek ep->e_vm.vm_dsize = 0;
63852405Storek ep->e_vm.vm_ssize = 0;
63952405Storek #ifndef sparc
64052405Storek /* ep->e_vm.vm_pmap = XXX; */
64152405Storek #endif
64252405Storek } else {
64352405Storek register struct vmspace *vm = p->p_vmspace;
64452405Storek
64565548Smckusick #ifdef pmap_resident_count
64665548Smckusick ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
64765548Smckusick #else
64852405Storek ep->e_vm.vm_rssize = vm->vm_rssize;
64965548Smckusick #endif
65052405Storek ep->e_vm.vm_tsize = vm->vm_tsize;
65152405Storek ep->e_vm.vm_dsize = vm->vm_dsize;
65252405Storek ep->e_vm.vm_ssize = vm->vm_ssize;
65352405Storek #ifndef sparc
65452405Storek ep->e_vm.vm_pmap = vm->vm_pmap;
65552405Storek #endif
65652405Storek }
65749141Skarels if (p->p_pptr)
65849141Skarels ep->e_ppid = p->p_pptr->p_pid;
65949141Skarels else
66049141Skarels ep->e_ppid = 0;
66148407Skarels ep->e_pgid = p->p_pgrp->pg_id;
66248407Skarels ep->e_jobc = p->p_pgrp->pg_jobc;
66364573Sbostic if ((p->p_flag & P_CONTROLT) &&
66448407Skarels (tp = ep->e_sess->s_ttyp)) {
66548407Skarels ep->e_tdev = tp->t_dev;
66650022Skarels ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
66748407Skarels ep->e_tsess = tp->t_session;
66848407Skarels } else
66948407Skarels ep->e_tdev = NODEV;
67048407Skarels ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
67148407Skarels if (SESS_LEADER(p))
67248407Skarels ep->e_flag |= EPROC_SLEADER;
67348407Skarels if (p->p_wmesg)
67448407Skarels strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
67548407Skarels ep->e_xsize = ep->e_xrssize = 0;
67648407Skarels ep->e_xccount = ep->e_xswrss = 0;
67748407Skarels }
67850149Smarc
67957843Smckusick #ifdef COMPAT_43
68057843Smckusick #include <sys/socket.h>
68157906Smckusick #define KINFO_PROC (0<<8)
68257906Smckusick #define KINFO_RT (1<<8)
68357906Smckusick #define KINFO_VNODE (2<<8)
68457906Smckusick #define KINFO_FILE (3<<8)
68557906Smckusick #define KINFO_METER (4<<8)
68657906Smckusick #define KINFO_LOADAVG (5<<8)
68757906Smckusick #define KINFO_CLOCKRATE (6<<8)
68857843Smckusick
68968298Scgd compat_43_getkerninfo(p, uap, retval)
69057843Smckusick struct proc *p;
69168298Scgd register struct compat_43_getkerninfo_args /* {
69268298Scgd syscallarg(int) op;
69368298Scgd syscallarg(char *) where;
69468298Scgd syscallarg(int *) size;
69568298Scgd syscallarg(int) arg;
69668298Scgd } */ *uap;
69768298Scgd register_t *retval;
69850149Smarc {
69957843Smckusick int error, name[5];
70068298Scgd size_t size;
70150149Smarc
70268298Scgd if (SCARG(uap, size) && (error = copyin((caddr_t)SCARG(uap, size),
70368298Scgd (caddr_t)&size, sizeof(size))))
70457843Smckusick return (error);
70550149Smarc
70668298Scgd switch (SCARG(uap, op) & 0xff00) {
70750149Smarc
70857843Smckusick case KINFO_RT:
70957843Smckusick name[0] = PF_ROUTE;
71057843Smckusick name[1] = 0;
71168298Scgd name[2] = (SCARG(uap, op) & 0xff0000) >> 16;
71268298Scgd name[3] = SCARG(uap, op) & 0xff;
71368298Scgd name[4] = SCARG(uap, arg);
71468298Scgd error =
71568298Scgd net_sysctl(name, 5, SCARG(uap, where), &size, NULL, 0, p);
71657843Smckusick break;
71757843Smckusick
71857843Smckusick case KINFO_VNODE:
71957843Smckusick name[0] = KERN_VNODE;
72068298Scgd error =
72168298Scgd kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
72257843Smckusick break;
72357843Smckusick
72457843Smckusick case KINFO_PROC:
72557843Smckusick name[0] = KERN_PROC;
72668298Scgd name[1] = SCARG(uap, op) & 0xff;
72768298Scgd name[2] = SCARG(uap, arg);
72868298Scgd error =
72968298Scgd kern_sysctl(name, 3, SCARG(uap, where), &size, NULL, 0, p);
73057843Smckusick break;
73157843Smckusick
73257843Smckusick case KINFO_FILE:
73357843Smckusick name[0] = KERN_FILE;
73468298Scgd error =
73568298Scgd kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
73657843Smckusick break;
73757843Smckusick
73857843Smckusick case KINFO_METER:
73957843Smckusick name[0] = VM_METER;
74068298Scgd error =
74168298Scgd vm_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
74257843Smckusick break;
74357843Smckusick
74457843Smckusick case KINFO_LOADAVG:
74557843Smckusick name[0] = VM_LOADAVG;
74668298Scgd error =
74768298Scgd vm_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
74857843Smckusick break;
74957843Smckusick
75057843Smckusick case KINFO_CLOCKRATE:
75157843Smckusick name[0] = KERN_CLOCKRATE;
75268298Scgd error =
75368298Scgd kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
75457843Smckusick break;
75557843Smckusick
75657843Smckusick default:
75758415Smckusick return (EOPNOTSUPP);
75850149Smarc }
75957843Smckusick if (error)
76057843Smckusick return (error);
76157843Smckusick *retval = size;
76268298Scgd if (SCARG(uap, size))
76368298Scgd error = copyout((caddr_t)&size, (caddr_t)SCARG(uap, size),
76458461Smckusick sizeof(size));
76558461Smckusick return (error);
76650149Smarc }
76757843Smckusick #endif /* COMPAT_43 */
768