157843Smckusick /*- 257843Smckusick * Copyright (c) 1982, 1986, 1989, 1993 Regents of the University of California. 339963Smarc * All rights reserved. 439963Smarc * 557843Smckusick * This code is derived from software contributed to Berkeley by 657843Smckusick * Mike Karels at Berkeley Software Design, Inc. 757843Smckusick * 844435Sbostic * %sccs.include.redist.c% 939963Smarc * 10*60153Smckusick * @(#)kern_sysctl.c 7.41 (Berkeley) 05/20/93 1139963Smarc */ 1239963Smarc 1357843Smckusick /* 1457843Smckusick * sysctl system call. 1557843Smckusick */ 1657843Smckusick 1756517Sbostic #include <sys/param.h> 1857843Smckusick #include <sys/systm.h> 19*60153Smckusick #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 3157843Smckusick sysctlfn kern_sysctl; 3257843Smckusick sysctlfn hw_sysctl; 3359161Smckusick #ifdef DEBUG 3459161Smckusick sysctlfn debug_sysctl; 3559161Smckusick #endif 3657843Smckusick extern sysctlfn vm_sysctl; 3757843Smckusick extern sysctlfn fs_sysctl; 3857843Smckusick extern sysctlfn net_sysctl; 3957843Smckusick extern sysctlfn cpu_sysctl; 4040068Smarc 4157843Smckusick /* 4257843Smckusick * Locking and stats 4357843Smckusick */ 4457843Smckusick static struct sysctl_lock { 4557843Smckusick int sl_lock; 4657843Smckusick int sl_want; 4757843Smckusick int sl_locked; 4857843Smckusick } memlock; 4957843Smckusick 5057843Smckusick struct sysctl_args { 5157843Smckusick int *name; 5257843Smckusick u_int namelen; 5357843Smckusick void *old; 5458466Sbostic size_t *oldlenp; 5557843Smckusick void *new; 5658466Sbostic size_t newlen; 5754923Storek }; 5857843Smckusick 5959718Sbostic int 6059718Sbostic __sysctl(p, uap, retval) 6143444Smckusick struct proc *p; 6257843Smckusick register struct sysctl_args *uap; 6343444Smckusick int *retval; 6443444Smckusick { 6557843Smckusick int error, dolock = 1; 6657843Smckusick u_int savelen, oldlen = 0; 6757843Smckusick sysctlfn *fn; 6857843Smckusick int name[CTL_MAXNAME]; 6939963Smarc 7057843Smckusick if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 7157843Smckusick return (error); 7257843Smckusick /* 7357843Smckusick * all top-level sysctl names are non-terminal 7457843Smckusick */ 7557843Smckusick if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 7657843Smckusick return (EINVAL); 7757843Smckusick if (error = copyin(uap->name, &name, uap->namelen * sizeof(int))) 7857843Smckusick return (error); 7939963Smarc 8057843Smckusick switch (name[0]) { 8157843Smckusick case CTL_KERN: 8257843Smckusick fn = kern_sysctl; 8357843Smckusick if (name[2] != KERN_VNODE) /* XXX */ 8457843Smckusick dolock = 0; 8539963Smarc break; 8657843Smckusick case CTL_HW: 8757843Smckusick fn = hw_sysctl; 8840068Smarc break; 8957843Smckusick case CTL_VM: 9057843Smckusick fn = vm_sysctl; 9141181Smarc break; 9257843Smckusick case CTL_NET: 9357843Smckusick fn = net_sysctl; 9450149Smarc break; 9557843Smckusick #ifdef notyet 9657843Smckusick case CTL_FS: 9757843Smckusick fn = fs_sysctl; 9850909Smckusick break; 9957843Smckusick case CTL_MACHDEP: 10057843Smckusick fn = cpu_sysctl; 10152669Smckusick break; 10257843Smckusick #endif 10359161Smckusick #ifdef DEBUG 10459161Smckusick case CTL_DEBUG: 10559161Smckusick fn = debug_sysctl; 10659161Smckusick break; 10759161Smckusick #endif 10839963Smarc default: 10957843Smckusick return (EOPNOTSUPP); 11039963Smarc } 11157843Smckusick 11257843Smckusick if (uap->oldlenp && 11357843Smckusick (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen)))) 11457843Smckusick return (error); 11557843Smckusick if (uap->old != NULL) { 11657843Smckusick if (!useracc(uap->old, oldlen, B_WRITE)) 11757843Smckusick return (EFAULT); 11857843Smckusick while (memlock.sl_lock) { 11957843Smckusick memlock.sl_want = 1; 12057843Smckusick sleep((caddr_t)&memlock, PRIBIO+1); 12157843Smckusick memlock.sl_locked++; 12257843Smckusick } 12357843Smckusick memlock.sl_lock = 1; 12457843Smckusick if (dolock) 12557843Smckusick vslock(uap->old, oldlen); 12657843Smckusick savelen = oldlen; 12740813Smarc } 12857843Smckusick error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen, 12958415Smckusick uap->new, uap->newlen, p); 13057843Smckusick if (uap->old != NULL) { 13157843Smckusick if (dolock) 13257843Smckusick vsunlock(uap->old, savelen, B_WRITE); 13357843Smckusick memlock.sl_lock = 0; 13457843Smckusick if (memlock.sl_want) { 13557843Smckusick memlock.sl_want = 0; 13657843Smckusick wakeup((caddr_t)&memlock); 13757843Smckusick } 13840206Smarc } 13957843Smckusick if (error) 14057843Smckusick return (error); 14157843Smckusick if (uap->oldlenp) 14257843Smckusick error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen)); 14357843Smckusick *retval = oldlen; 14457843Smckusick return (0); 14557843Smckusick } 14640206Smarc 14757843Smckusick /* 14857843Smckusick * Attributes stored in the kernel. 14957843Smckusick */ 15057843Smckusick char hostname[MAXHOSTNAMELEN]; 15157843Smckusick int hostnamelen; 15257843Smckusick long hostid; 15358415Smckusick int securelevel; 15457843Smckusick 15558415Smckusick /* 15658415Smckusick * kernel related system variables. 15758415Smckusick */ 15858415Smckusick kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 15957843Smckusick int *name; 16057843Smckusick u_int namelen; 16157843Smckusick void *oldp; 16258466Sbostic size_t *oldlenp; 16357843Smckusick void *newp; 16458466Sbostic size_t newlen; 16558415Smckusick struct proc *p; 16657843Smckusick { 16758415Smckusick int error, level; 16857843Smckusick extern char ostype[], osrelease[], version[]; 16957843Smckusick 17057843Smckusick /* all sysctl names at this level are terminal */ 17159312Smckusick if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF)) 17257843Smckusick return (ENOTDIR); /* overloaded */ 17357843Smckusick 17457843Smckusick switch (name[0]) { 17557843Smckusick case KERN_OSTYPE: 17657843Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 17757843Smckusick case KERN_OSRELEASE: 17857843Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 17957843Smckusick case KERN_OSREV: 18057843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, BSD)); 18157843Smckusick case KERN_VERSION: 18257843Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, version)); 18359718Sbostic case KERN_MAXVNODES: 18459718Sbostic return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes)); 18557843Smckusick case KERN_MAXPROC: 18657843Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 18757843Smckusick case KERN_MAXFILES: 18857843Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 18957843Smckusick case KERN_ARGMAX: 19057843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 19158415Smckusick case KERN_SECURELVL: 19258415Smckusick level = securelevel; 19358415Smckusick if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 19458415Smckusick newp == NULL) 19558415Smckusick return (error); 19658415Smckusick if (level < securelevel && p->p_pid != 1) 19758415Smckusick return (EPERM); 19858415Smckusick securelevel = level; 19958415Smckusick return (0); 20059718Sbostic case KERN_HOSTNAME: 20159718Sbostic error = sysctl_string(oldp, oldlenp, newp, newlen, 20259718Sbostic hostname, sizeof(hostname)); 20359718Sbostic if (!error) 20459718Sbostic hostnamelen = newlen; 20559718Sbostic return (error); 20659718Sbostic case KERN_HOSTID: 20759718Sbostic return (sysctl_int(oldp, oldlenp, newp, newlen, &hostid)); 20857843Smckusick case KERN_CLOCKRATE: 20957843Smckusick return (sysctl_clockrate(oldp, oldlenp)); 210*60153Smckusick case KERN_BOOTTIME: 211*60153Smckusick return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 212*60153Smckusick sizeof(struct timeval))); 21357843Smckusick case KERN_VNODE: 21457843Smckusick return (sysctl_vnode(oldp, oldlenp)); 21557843Smckusick case KERN_PROC: 21657843Smckusick return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 21759718Sbostic case KERN_FILE: 21859718Sbostic return (sysctl_file(oldp, oldlenp)); 21959312Smckusick #ifdef GPROF 22059312Smckusick case KERN_PROF: 22159312Smckusick return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 22259312Smckusick newp, newlen)); 22359312Smckusick #endif 22459718Sbostic case KERN_POSIX1: 22559718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 22659718Sbostic case KERN_NGROUPS: 22759718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 22859718Sbostic case KERN_JOB_CONTROL: 22959718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, 1)); 23059718Sbostic case KERN_SAVED_IDS: 23159718Sbostic #ifdef _POSIX_SAVED_IDS 23259718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, 1)); 23359718Sbostic #else 23459718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, 0)); 23559718Sbostic #endif 23659718Sbostic case KERN_LINK_MAX: 23759718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, LINK_MAX)); 23859718Sbostic case KERN_MAX_CANON: 23959718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, MAX_CANON)); 24059718Sbostic case KERN_MAX_INPUT: 24159718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, MAX_INPUT)); 24259718Sbostic case KERN_NAME_MAX: 24359718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, NAME_MAX)); 24459718Sbostic case KERN_PATH_MAX: 24559718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, PATH_MAX)); 24659718Sbostic case KERN_PIPE_BUF: 24759718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, PIPE_BUF)); 24859718Sbostic case KERN_CHOWN_RESTRICTED: 24959718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, 1)); 25059718Sbostic case KERN_NO_TRUNC: 25159749Smckusick return (sysctl_rdint(oldp, oldlenp, newp, 1)); 25259718Sbostic case KERN_VDISABLE: 25359718Sbostic return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VDISABLE)); 25457843Smckusick default: 25557843Smckusick return (EOPNOTSUPP); 25652405Storek } 25757843Smckusick /* NOTREACHED */ 25857843Smckusick } 25957843Smckusick 26058415Smckusick /* 26158415Smckusick * hardware related system variables. 26258415Smckusick */ 26358415Smckusick hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 26457843Smckusick int *name; 26557843Smckusick u_int namelen; 26657843Smckusick void *oldp; 26758466Sbostic size_t *oldlenp; 26857843Smckusick void *newp; 26958466Sbostic size_t newlen; 27058415Smckusick struct proc *p; 27157843Smckusick { 27257843Smckusick extern char machine[], cpu_model[]; 27357843Smckusick 27457843Smckusick /* all sysctl names at this level are terminal */ 27557843Smckusick if (namelen != 1) 27657843Smckusick return (ENOTDIR); /* overloaded */ 27757843Smckusick 27857843Smckusick switch (name[0]) { 27957843Smckusick case HW_MACHINE: 28057843Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 28157843Smckusick case HW_MODEL: 28257843Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 28357843Smckusick case HW_NCPU: 28457843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 28559618Smckusick case HW_BYTEORDER: 28659618Smckusick return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 28757843Smckusick case HW_PHYSMEM: 28857843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 28957843Smckusick case HW_USERMEM: 29057843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, 29157843Smckusick ctob(physmem - cnt.v_wire_count))); 29257843Smckusick case HW_PAGESIZE: 29357843Smckusick return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 29457843Smckusick default: 29557843Smckusick return (EOPNOTSUPP); 29657843Smckusick } 29757843Smckusick /* NOTREACHED */ 29857843Smckusick } 29957843Smckusick 30059161Smckusick #ifdef DEBUG 30157843Smckusick /* 30259161Smckusick * Debugging related system variables. 30359161Smckusick */ 30459161Smckusick struct ctldebug debug0, debug1, debug2, debug3, debug4; 30559161Smckusick struct ctldebug debug5, debug6, debug7, debug8, debug9; 30659161Smckusick struct ctldebug debug10, debug11, debug12, debug13, debug14; 30759161Smckusick struct ctldebug debug15, debug16, debug17, debug18, debug19; 30859161Smckusick static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 30959161Smckusick &debug0, &debug1, &debug2, &debug3, &debug4, 31059161Smckusick &debug5, &debug6, &debug7, &debug8, &debug9, 31159161Smckusick &debug10, &debug11, &debug12, &debug13, &debug14, 31259161Smckusick &debug15, &debug16, &debug17, &debug18, &debug19, 31359161Smckusick }; 31459161Smckusick int 31559161Smckusick debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 31659161Smckusick int *name; 31759161Smckusick u_int namelen; 31859161Smckusick void *oldp; 31959161Smckusick size_t *oldlenp; 32059161Smckusick void *newp; 32159161Smckusick size_t newlen; 32259161Smckusick struct proc *p; 32359161Smckusick { 32459161Smckusick struct ctldebug *cdp; 32559161Smckusick 32659161Smckusick /* all sysctl names at this level are name and field */ 32759161Smckusick if (namelen != 2) 32859161Smckusick return (ENOTDIR); /* overloaded */ 32959161Smckusick cdp = debugvars[name[0]]; 33059161Smckusick if (cdp->debugname == 0) 33159161Smckusick return (EOPNOTSUPP); 33259161Smckusick switch (name[1]) { 33359161Smckusick case CTL_DEBUG_NAME: 33459161Smckusick return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 33559161Smckusick case CTL_DEBUG_VALUE: 33659161Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 33759161Smckusick default: 33859161Smckusick return (EOPNOTSUPP); 33959161Smckusick } 34059161Smckusick /* NOTREACHED */ 34159161Smckusick } 34259161Smckusick #endif /* DEBUG */ 34359161Smckusick 34459161Smckusick /* 34557843Smckusick * Validate parameters and get old / set new parameters 34657843Smckusick * for an integer-valued sysctl function. 34757843Smckusick */ 34857843Smckusick sysctl_int(oldp, oldlenp, newp, newlen, valp) 34957843Smckusick void *oldp; 35058466Sbostic size_t *oldlenp; 35157843Smckusick void *newp; 35258466Sbostic size_t newlen; 35357843Smckusick int *valp; 35457843Smckusick { 35557843Smckusick int error = 0; 35657843Smckusick 35757843Smckusick if (oldp && *oldlenp < sizeof(int)) 35857843Smckusick return (ENOMEM); 35957843Smckusick if (newp && newlen != sizeof(int)) 36057843Smckusick return (EINVAL); 36157843Smckusick *oldlenp = sizeof(int); 36257843Smckusick if (oldp) 36357843Smckusick error = copyout(valp, oldp, sizeof(int)); 36457843Smckusick if (error == 0 && newp) 36557843Smckusick error = copyin(newp, valp, sizeof(int)); 36643444Smckusick return (error); 36739963Smarc } 36839963Smarc 36957843Smckusick /* 37057843Smckusick * As above, but read-only. 37157843Smckusick */ 37257843Smckusick sysctl_rdint(oldp, oldlenp, newp, val) 37357843Smckusick void *oldp; 37458466Sbostic size_t *oldlenp; 37557843Smckusick void *newp; 37657843Smckusick int val; 37757843Smckusick { 37857843Smckusick int error = 0; 37957843Smckusick 38057843Smckusick if (oldp && *oldlenp < sizeof(int)) 38157843Smckusick return (ENOMEM); 38257843Smckusick if (newp) 38357843Smckusick return (EPERM); 38457843Smckusick *oldlenp = sizeof(int); 38557843Smckusick if (oldp) 38657843Smckusick error = copyout((caddr_t)&val, oldp, sizeof(int)); 38757843Smckusick return (error); 38857843Smckusick } 38957843Smckusick 39057843Smckusick /* 39157843Smckusick * Validate parameters and get old / set new parameters 39257843Smckusick * for a string-valued sysctl function. 39357843Smckusick */ 39457843Smckusick sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 39557843Smckusick void *oldp; 39658466Sbostic size_t *oldlenp; 39757843Smckusick void *newp; 39858466Sbostic size_t newlen; 39957843Smckusick char *str; 40057843Smckusick int maxlen; 40157843Smckusick { 40257843Smckusick int len, error = 0; 40357843Smckusick 40457843Smckusick len = strlen(str) + 1; 40557843Smckusick if (oldp && *oldlenp < len) 40657843Smckusick return (ENOMEM); 40757843Smckusick if (newp && newlen >= maxlen) 40857843Smckusick return (EINVAL); 40958128Sralph if (oldp) { 41058128Sralph *oldlenp = len; 41157843Smckusick error = copyout(str, oldp, len); 41258128Sralph } 41357843Smckusick if (error == 0 && newp) { 41457843Smckusick error = copyin(newp, str, newlen); 41557843Smckusick str[newlen] = 0; 41657843Smckusick } 41757843Smckusick return (error); 41857843Smckusick } 41957843Smckusick 42057843Smckusick /* 42157843Smckusick * As above, but read-only. 42257843Smckusick */ 42357843Smckusick sysctl_rdstring(oldp, oldlenp, newp, str) 42457843Smckusick void *oldp; 42558466Sbostic size_t *oldlenp; 42657843Smckusick void *newp; 42757843Smckusick char *str; 42857843Smckusick { 42957843Smckusick int len, error = 0; 43057843Smckusick 43157843Smckusick len = strlen(str) + 1; 43257843Smckusick if (oldp && *oldlenp < len) 43357843Smckusick return (ENOMEM); 43457843Smckusick if (newp) 43557843Smckusick return (EPERM); 43657843Smckusick *oldlenp = len; 43757843Smckusick if (oldp) 43857843Smckusick error = copyout(str, oldp, len); 43957843Smckusick return (error); 44057843Smckusick } 44157843Smckusick 44257843Smckusick /* 44359312Smckusick * Validate parameters and get old / set new parameters 44459312Smckusick * for a structure oriented sysctl function. 44559312Smckusick */ 44659312Smckusick sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 44759312Smckusick void *oldp; 44859312Smckusick size_t *oldlenp; 44959312Smckusick void *newp; 45059312Smckusick size_t newlen; 45159312Smckusick void *sp; 45259312Smckusick int len; 45359312Smckusick { 45459312Smckusick int error = 0; 45559312Smckusick 45659312Smckusick if (oldp && *oldlenp < len) 45759312Smckusick return (ENOMEM); 45859312Smckusick if (newp && newlen > len) 45959312Smckusick return (EINVAL); 46059312Smckusick if (oldp) { 46159312Smckusick *oldlenp = len; 46259312Smckusick error = copyout(sp, oldp, len); 46359312Smckusick } 46459312Smckusick if (error == 0 && newp) 46559312Smckusick error = copyin(newp, sp, len); 46659312Smckusick return (error); 46759312Smckusick } 46859312Smckusick 46959312Smckusick /* 47057843Smckusick * Validate parameters and get old parameters 47157843Smckusick * for a structure oriented sysctl function. 47257843Smckusick */ 47357843Smckusick sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 47457843Smckusick void *oldp; 47558466Sbostic size_t *oldlenp; 47658466Sbostic void *newp, *sp; 47757843Smckusick int len; 47857843Smckusick { 47957843Smckusick int error = 0; 48057843Smckusick 48157843Smckusick if (oldp && *oldlenp < len) 48257843Smckusick return (ENOMEM); 48357843Smckusick if (newp) 48457843Smckusick return (EPERM); 48557843Smckusick *oldlenp = len; 48657843Smckusick if (oldp) 48757843Smckusick error = copyout(sp, oldp, len); 48857843Smckusick return (error); 48957843Smckusick } 49057843Smckusick 49157843Smckusick /* 49257843Smckusick * Get file structures. 49357843Smckusick */ 49457843Smckusick sysctl_file(where, sizep) 49557843Smckusick char *where; 49658466Sbostic size_t *sizep; 49757843Smckusick { 49857843Smckusick int buflen, error; 49957843Smckusick struct file *fp; 50057843Smckusick char *start = where; 50157843Smckusick 50257843Smckusick buflen = *sizep; 50357843Smckusick if (where == NULL) { 50457843Smckusick /* 50557843Smckusick * overestimate by 10 files 50657843Smckusick */ 50757843Smckusick *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 50857843Smckusick return (0); 50957843Smckusick } 51057843Smckusick 51157843Smckusick /* 51257843Smckusick * first copyout filehead 51357843Smckusick */ 51457843Smckusick if (buflen < sizeof(filehead)) { 51557843Smckusick *sizep = 0; 51657843Smckusick return (0); 51757843Smckusick } 51857843Smckusick if (error = copyout((caddr_t)&filehead, where, sizeof(filehead))) 51957843Smckusick return (error); 52057843Smckusick buflen += sizeof(filehead); 52157843Smckusick where += sizeof(filehead); 52257843Smckusick 52357843Smckusick /* 52457843Smckusick * followed by an array of file structures 52557843Smckusick */ 52657843Smckusick for (fp = filehead; fp != NULL; fp = fp->f_filef) { 52757843Smckusick if (buflen < sizeof(struct file)) { 52857843Smckusick *sizep = where - start; 52957843Smckusick return (ENOMEM); 53057843Smckusick } 53157843Smckusick if (error = copyout((caddr_t)fp, where, sizeof (struct file))) 53257843Smckusick return (error); 53357843Smckusick buflen -= sizeof(struct file); 53457843Smckusick where += sizeof(struct file); 53557843Smckusick } 53657843Smckusick *sizep = where - start; 53757843Smckusick return (0); 53857843Smckusick } 53957843Smckusick 54059312Smckusick /* 54159312Smckusick * try over estimating by 5 procs 54239963Smarc */ 54357843Smckusick #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 54439963Smarc 54557843Smckusick sysctl_doproc(name, namelen, where, sizep) 54657843Smckusick int *name; 54758466Sbostic u_int namelen; 54839963Smarc char *where; 54958466Sbostic size_t *sizep; 55039963Smarc { 55139963Smarc register struct proc *p; 55243419Smarc register struct kinfo_proc *dp = (struct kinfo_proc *)where; 55357843Smckusick register int needed = 0; 55457843Smckusick int buflen = where != NULL ? *sizep : 0; 55539963Smarc int doingzomb; 55640067Smarc struct eproc eproc; 55739963Smarc int error = 0; 55839963Smarc 55959977Smckusick if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 56057843Smckusick return (EINVAL); 56154755Storek p = (struct proc *)allproc; 56239963Smarc doingzomb = 0; 56339963Smarc again: 56439963Smarc for (; p != NULL; p = p->p_nxt) { 56553819Smckusick /* 56653819Smckusick * Skip embryonic processes. 56753819Smckusick */ 56853819Smckusick if (p->p_stat == SIDL) 56953819Smckusick continue; 57059312Smckusick /* 57139963Smarc * TODO - make more efficient (see notes below). 57259312Smckusick * do by session. 57339963Smarc */ 57457843Smckusick switch (name[0]) { 57539963Smarc 57657843Smckusick case KERN_PROC_PID: 57739963Smarc /* could do this with just a lookup */ 57857843Smckusick if (p->p_pid != (pid_t)name[1]) 57939963Smarc continue; 58039963Smarc break; 58139963Smarc 58257843Smckusick case KERN_PROC_PGRP: 58339963Smarc /* could do this by traversing pgrp */ 58457843Smckusick if (p->p_pgrp->pg_id != (pid_t)name[1]) 58539963Smarc continue; 58639963Smarc break; 58739963Smarc 58857843Smckusick case KERN_PROC_TTY: 58959312Smckusick if ((p->p_flag&SCTTY) == 0 || 59039963Smarc p->p_session->s_ttyp == NULL || 59157843Smckusick p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 59239963Smarc continue; 59339963Smarc break; 59439963Smarc 59557843Smckusick case KERN_PROC_UID: 59657843Smckusick if (p->p_ucred->cr_uid != (uid_t)name[1]) 59739963Smarc continue; 59839963Smarc break; 59939963Smarc 60057843Smckusick case KERN_PROC_RUID: 60157843Smckusick if (p->p_cred->p_ruid != (uid_t)name[1]) 60239963Smarc continue; 60339963Smarc break; 60439963Smarc } 60557843Smckusick if (buflen >= sizeof(struct kinfo_proc)) { 60648407Skarels fill_eproc(p, &eproc); 60759312Smckusick if (error = copyout((caddr_t)p, &dp->kp_proc, 60857843Smckusick sizeof(struct proc))) 60939963Smarc return (error); 61059312Smckusick if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 61157843Smckusick sizeof(eproc))) 61239963Smarc return (error); 61343419Smarc dp++; 61457843Smckusick buflen -= sizeof(struct kinfo_proc); 61539963Smarc } 61657843Smckusick needed += sizeof(struct kinfo_proc); 61739963Smarc } 61839963Smarc if (doingzomb == 0) { 61939963Smarc p = zombproc; 62039963Smarc doingzomb++; 62139963Smarc goto again; 62239963Smarc } 62357843Smckusick if (where != NULL) { 62457843Smckusick *sizep = (caddr_t)dp - where; 62557843Smckusick if (needed > *sizep) 62657843Smckusick return (ENOMEM); 62757843Smckusick } else { 62857843Smckusick needed += KERN_PROCSLOP; 62957843Smckusick *sizep = needed; 63057843Smckusick } 63139963Smarc return (0); 63239963Smarc } 63348407Skarels 63448407Skarels /* 63548407Skarels * Fill in an eproc structure for the specified process. 63648407Skarels */ 63748407Skarels void 63848407Skarels fill_eproc(p, ep) 63948407Skarels register struct proc *p; 64048407Skarels register struct eproc *ep; 64148407Skarels { 64248407Skarels register struct tty *tp; 64348407Skarels 64448407Skarels ep->e_paddr = p; 64548407Skarels ep->e_sess = p->p_pgrp->pg_session; 64648407Skarels ep->e_pcred = *p->p_cred; 64748407Skarels ep->e_ucred = *p->p_ucred; 64852405Storek if (p->p_stat == SIDL || p->p_stat == SZOMB) { 64952405Storek ep->e_vm.vm_rssize = 0; 65052405Storek ep->e_vm.vm_tsize = 0; 65152405Storek ep->e_vm.vm_dsize = 0; 65252405Storek ep->e_vm.vm_ssize = 0; 65352405Storek #ifndef sparc 65452405Storek /* ep->e_vm.vm_pmap = XXX; */ 65552405Storek #endif 65652405Storek } else { 65752405Storek register struct vmspace *vm = p->p_vmspace; 65852405Storek 65952405Storek ep->e_vm.vm_rssize = vm->vm_rssize; 66052405Storek ep->e_vm.vm_tsize = vm->vm_tsize; 66152405Storek ep->e_vm.vm_dsize = vm->vm_dsize; 66252405Storek ep->e_vm.vm_ssize = vm->vm_ssize; 66352405Storek #ifndef sparc 66452405Storek ep->e_vm.vm_pmap = vm->vm_pmap; 66552405Storek #endif 66652405Storek } 66749141Skarels if (p->p_pptr) 66849141Skarels ep->e_ppid = p->p_pptr->p_pid; 66949141Skarels else 67049141Skarels ep->e_ppid = 0; 67148407Skarels ep->e_pgid = p->p_pgrp->pg_id; 67248407Skarels ep->e_jobc = p->p_pgrp->pg_jobc; 67359312Smckusick if ((p->p_flag&SCTTY) && 67448407Skarels (tp = ep->e_sess->s_ttyp)) { 67548407Skarels ep->e_tdev = tp->t_dev; 67650022Skarels ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 67748407Skarels ep->e_tsess = tp->t_session; 67848407Skarels } else 67948407Skarels ep->e_tdev = NODEV; 68048407Skarels ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 68148407Skarels if (SESS_LEADER(p)) 68248407Skarels ep->e_flag |= EPROC_SLEADER; 68348407Skarels if (p->p_wmesg) 68448407Skarels strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 68548407Skarels ep->e_xsize = ep->e_xrssize = 0; 68648407Skarels ep->e_xccount = ep->e_xswrss = 0; 68748407Skarels } 68850149Smarc 68957843Smckusick #ifdef COMPAT_43 69057843Smckusick #include <sys/socket.h> 69157906Smckusick #define KINFO_PROC (0<<8) 69257906Smckusick #define KINFO_RT (1<<8) 69357906Smckusick #define KINFO_VNODE (2<<8) 69457906Smckusick #define KINFO_FILE (3<<8) 69557906Smckusick #define KINFO_METER (4<<8) 69657906Smckusick #define KINFO_LOADAVG (5<<8) 69757906Smckusick #define KINFO_CLOCKRATE (6<<8) 69857843Smckusick 69957843Smckusick struct getkerninfo_args { 70057843Smckusick int op; 70157843Smckusick char *where; 70257843Smckusick int *size; 70357843Smckusick int arg; 70457843Smckusick }; 70557843Smckusick 70658943Smckusick ogetkerninfo(p, uap, retval) 70757843Smckusick struct proc *p; 70857843Smckusick register struct getkerninfo_args *uap; 70957843Smckusick int *retval; 71050149Smarc { 71157843Smckusick int error, name[5]; 71257843Smckusick u_int size; 71350149Smarc 71458461Smckusick if (uap->size && 71558466Sbostic (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size)))) 71657843Smckusick return (error); 71750149Smarc 71857906Smckusick switch (uap->op & 0xff00) { 71950149Smarc 72057843Smckusick case KINFO_RT: 72157843Smckusick name[0] = PF_ROUTE; 72257843Smckusick name[1] = 0; 72357843Smckusick name[2] = (uap->op & 0xff0000) >> 16; 72457843Smckusick name[3] = uap->op & 0xff; 72557843Smckusick name[4] = uap->arg; 72658415Smckusick error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p); 72757843Smckusick break; 72857843Smckusick 72957843Smckusick case KINFO_VNODE: 73057843Smckusick name[0] = KERN_VNODE; 73158415Smckusick error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 73257843Smckusick break; 73357843Smckusick 73457843Smckusick case KINFO_PROC: 73557843Smckusick name[0] = KERN_PROC; 73657843Smckusick name[1] = uap->op & 0xff; 73757843Smckusick name[2] = uap->arg; 73858415Smckusick error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p); 73957843Smckusick break; 74057843Smckusick 74157843Smckusick case KINFO_FILE: 74257843Smckusick name[0] = KERN_FILE; 74358415Smckusick error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 74457843Smckusick break; 74557843Smckusick 74657843Smckusick case KINFO_METER: 74757843Smckusick name[0] = VM_METER; 74858415Smckusick error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 74957843Smckusick break; 75057843Smckusick 75157843Smckusick case KINFO_LOADAVG: 75257843Smckusick name[0] = VM_LOADAVG; 75358415Smckusick error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 75457843Smckusick break; 75557843Smckusick 75657843Smckusick case KINFO_CLOCKRATE: 75757843Smckusick name[0] = KERN_CLOCKRATE; 75858415Smckusick error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 75957843Smckusick break; 76057843Smckusick 76157843Smckusick default: 76258415Smckusick return (EOPNOTSUPP); 76350149Smarc } 76457843Smckusick if (error) 76557843Smckusick return (error); 76657843Smckusick *retval = size; 76758461Smckusick if (uap->size) 76858461Smckusick error = copyout((caddr_t)&size, (caddr_t)uap->size, 76958461Smckusick sizeof(size)); 77058461Smckusick return (error); 77150149Smarc } 77257843Smckusick #endif /* COMPAT_43 */ 773