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*68657Smckusick * @(#)kern_sysctl.c 8.8 (Berkeley) 03/30/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; 40*68657Smckusick 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 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; 98*68657Smckusick case CTL_VFS: 99*68657Smckusick 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 */ 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: 21857843Smckusick return (sysctl_vnode(oldp, oldlenp)); 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 */ 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 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]]; 316*68657Smckusick 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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