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