kern_sysctl.c revision 1542
1231990Smp/*- 259243Sobrien * Copyright (c) 1982, 1986, 1989, 1993 359243Sobrien * The Regents of the University of California. All rights reserved. 459243Sobrien * 559243Sobrien * This code is derived from software contributed to Berkeley by 659243Sobrien * Mike Karels at Berkeley Software Design, Inc. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 1659243Sobrien * 3. All advertising materials mentioning features or use of this software 17100616Smp * must display the following acknowledgement: 1859243Sobrien * This product includes software developed by the University of 1959243Sobrien * California, Berkeley and its contributors. 2059243Sobrien * 4. Neither the name of the University nor the names of its contributors 2159243Sobrien * may be used to endorse or promote products derived from this software 2259243Sobrien * without specific prior written permission. 2359243Sobrien * 2459243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2559243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2659243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2759243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2859243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2959243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3059243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3159243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3259243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3359243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3459243Sobrien * SUCH DAMAGE. 35231990Smp * 3659243Sobrien * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 3759243Sobrien */ 3859243Sobrien 3959243Sobrien/* 40167465Smp * sysctl system call. 41167465Smp */ 42167465Smp 43167465Smp#include <sys/param.h> 44167465Smp#include <sys/systm.h> 45167465Smp#include <sys/kernel.h> 46167465Smp#include <sys/malloc.h> 47167465Smp#include <sys/proc.h> 48167465Smp#include <sys/file.h> 49167465Smp#include <sys/vnode.h> 5059243Sobrien#include <sys/unistd.h> 5159243Sobrien#include <sys/buf.h> 5259243Sobrien#include <sys/ioctl.h> 5359243Sobrien#include <sys/tty.h> 5459243Sobrien#include <vm/vm.h> 5559243Sobrien#include <sys/sysctl.h> 5659243Sobrien 5759243Sobriensysctlfn kern_sysctl; 5859243Sobriensysctlfn hw_sysctl; 5959243Sobrien#ifdef DEBUG 6059243Sobriensysctlfn debug_sysctl; 61167465Smp#endif 6259243Sobrienextern sysctlfn vm_sysctl; 63167465Smpextern sysctlfn fs_sysctl; 6459243Sobrienextern sysctlfn net_sysctl; 6559243Sobrienextern sysctlfn cpu_sysctl; 6659243Sobrien 67167465Smp/* 68167465Smp * Locking and stats 69167465Smp */ 70167465Smpstatic struct sysctl_lock { 7159243Sobrien int sl_lock; 7259243Sobrien int sl_want; 73167465Smp int sl_locked; 74167465Smp} memlock; 7559243Sobrien 76167465Smpstruct sysctl_args { 77167465Smp int *name; 78167465Smp u_int namelen; 79167465Smp void *old; 80167465Smp size_t *oldlenp; 81167465Smp void *new; 8259243Sobrien size_t newlen; 8359243Sobrien}; 84167465Smp 85167465Smpint 8659243Sobrien__sysctl(p, uap, retval) 87145479Smp struct proc *p; 88145479Smp register struct sysctl_args *uap; 8959243Sobrien int *retval; 9059243Sobrien{ 9159243Sobrien int error, dolock = 1; 9259243Sobrien u_int savelen, oldlen = 0; 9359243Sobrien sysctlfn *fn; 9459243Sobrien int name[CTL_MAXNAME]; 9559243Sobrien 9659243Sobrien if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 9759243Sobrien return (error); 9859243Sobrien /* 9959243Sobrien * all top-level sysctl names are non-terminal 10059243Sobrien */ 10159243Sobrien if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 10259243Sobrien return (EINVAL); 10359243Sobrien if (error = copyin(uap->name, &name, uap->namelen * sizeof(int))) 10459243Sobrien return (error); 10559243Sobrien 10659243Sobrien switch (name[0]) { 10759243Sobrien case CTL_KERN: 10859243Sobrien fn = kern_sysctl; 10959243Sobrien if (name[2] != KERN_VNODE) /* XXX */ 11059243Sobrien dolock = 0; 11159243Sobrien break; 11259243Sobrien case CTL_HW: 11359243Sobrien fn = hw_sysctl; 114167465Smp break; 115167465Smp case CTL_VM: 116167465Smp fn = vm_sysctl; 11759243Sobrien break; 11859243Sobrien case CTL_NET: 11959243Sobrien fn = net_sysctl; 12059243Sobrien break; 12159243Sobrien#ifdef notyet 122167465Smp case CTL_FS: 123167465Smp fn = fs_sysctl; 12459243Sobrien break; 12559243Sobrien#endif 12659243Sobrien case CTL_MACHDEP: 127167465Smp fn = cpu_sysctl; 12859243Sobrien break; 129167465Smp#ifdef DEBUG 130167465Smp case CTL_DEBUG: 131167465Smp fn = debug_sysctl; 132167465Smp break; 133167465Smp#endif 134167465Smp default: 135167465Smp return (EOPNOTSUPP); 136167465Smp } 137167465Smp 138145479Smp if (uap->oldlenp && 13959243Sobrien (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen)))) 140145479Smp return (error); 14159243Sobrien if (uap->old != NULL) { 14259243Sobrien if (!useracc(uap->old, oldlen, B_WRITE)) 143167465Smp return (EFAULT); 14459243Sobrien while (memlock.sl_lock) { 14559243Sobrien memlock.sl_want = 1; 14659243Sobrien sleep((caddr_t)&memlock, PRIBIO+1); 147167465Smp memlock.sl_locked++; 14859243Sobrien } 149167465Smp memlock.sl_lock = 1; 150167465Smp if (dolock) 15159243Sobrien vslock(uap->old, oldlen); 15259243Sobrien savelen = oldlen; 15359243Sobrien } 154167465Smp error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen, 15559243Sobrien uap->new, uap->newlen, p); 15659243Sobrien if (uap->old != NULL) { 15759243Sobrien if (dolock) 158167465Smp vsunlock(uap->old, savelen, B_WRITE); 15959243Sobrien memlock.sl_lock = 0; 160167465Smp if (memlock.sl_want) { 16159243Sobrien memlock.sl_want = 0; 16259243Sobrien wakeup((caddr_t)&memlock); 16359243Sobrien } 16459243Sobrien } 16559243Sobrien if (error) 16659243Sobrien return (error); 16759243Sobrien if (uap->oldlenp) 16859243Sobrien error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen)); 169167465Smp *retval = oldlen; 17059243Sobrien return (0); 17159243Sobrien} 17259243Sobrien 17359243Sobrien/* 17459243Sobrien * Attributes stored in the kernel. 17559243Sobrien */ 17659243Sobrienchar hostname[MAXHOSTNAMELEN]; 177167465Smpint hostnamelen; 178167465Smplong hostid; 17959243Sobrienint securelevel; 180167465Smp 18159243Sobrien/* 18259243Sobrien * kernel related system variables. 18359243Sobrien */ 184167465Smpkern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 18559243Sobrien int *name; 186145479Smp u_int namelen; 18759243Sobrien void *oldp; 18859243Sobrien size_t *oldlenp; 189167465Smp void *newp; 19059243Sobrien size_t newlen; 191167465Smp struct proc *p; 19259243Sobrien{ 19359243Sobrien int error, level, inthostid; 19459243Sobrien extern char ostype[], osrelease[], version[]; 19559243Sobrien 19659243Sobrien /* all sysctl names at this level are terminal */ 19759243Sobrien if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF)) 19859243Sobrien return (ENOTDIR); /* overloaded */ 19959243Sobrien 20059243Sobrien switch (name[0]) { 20159243Sobrien case KERN_OSTYPE: 20259243Sobrien return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 20359243Sobrien case KERN_OSRELEASE: 20459243Sobrien return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 20559243Sobrien case KERN_OSREV: 20659243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, BSD)); 20759243Sobrien case KERN_VERSION: 20859243Sobrien return (sysctl_rdstring(oldp, oldlenp, newp, version)); 209167465Smp case KERN_MAXVNODES: 21059243Sobrien return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes)); 21159243Sobrien case KERN_MAXPROC: 21259243Sobrien return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 21359243Sobrien case KERN_MAXFILES: 21459243Sobrien return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 21559243Sobrien case KERN_ARGMAX: 21659243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 21759243Sobrien case KERN_SECURELVL: 21859243Sobrien level = securelevel; 21959243Sobrien if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 22059243Sobrien newp == NULL) 22159243Sobrien return (error); 22259243Sobrien if (level < securelevel && p->p_pid != 1) 22359243Sobrien return (EPERM); 22459243Sobrien securelevel = level; 22559243Sobrien return (0); 226167465Smp case KERN_HOSTNAME: 22759243Sobrien error = sysctl_string(oldp, oldlenp, newp, newlen, 228167465Smp hostname, sizeof(hostname)); 229145479Smp if (newp && !error) 23059243Sobrien hostnamelen = newlen; 23159243Sobrien return (error); 23259243Sobrien case KERN_HOSTID: 23359243Sobrien inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 23459243Sobrien error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 23559243Sobrien hostid = inthostid; 23659243Sobrien return (error); 23759243Sobrien case KERN_CLOCKRATE: 23859243Sobrien return (sysctl_clockrate(oldp, oldlenp)); 23959243Sobrien case KERN_BOOTTIME: 24059243Sobrien return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 24159243Sobrien sizeof(struct timeval))); 24259243Sobrien case KERN_VNODE: 24359243Sobrien return (sysctl_vnode(oldp, oldlenp)); 24459243Sobrien case KERN_PROC: 24559243Sobrien return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 24659243Sobrien case KERN_FILE: 24759243Sobrien return (sysctl_file(oldp, oldlenp)); 24859243Sobrien#ifdef GPROF 24959243Sobrien case KERN_PROF: 25059243Sobrien return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 25159243Sobrien newp, newlen)); 25259243Sobrien#endif 25359243Sobrien case KERN_POSIX1: 25459243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 25559243Sobrien case KERN_NGROUPS: 25659243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 25759243Sobrien case KERN_JOB_CONTROL: 25859243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, 1)); 25959243Sobrien case KERN_SAVED_IDS: 26059243Sobrien#ifdef _POSIX_SAVED_IDS 26159243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, 1)); 26259243Sobrien#else 26359243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, 0)); 26459243Sobrien#endif 265167465Smp default: 26659243Sobrien return (EOPNOTSUPP); 26759243Sobrien } 26859243Sobrien /* NOTREACHED */ 26959243Sobrien} 27059243Sobrien 27159243Sobrien/* 27259243Sobrien * hardware related system variables. 273167465Smp */ 27459243Sobrienhw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 27559243Sobrien int *name; 27659243Sobrien u_int namelen; 27759243Sobrien void *oldp; 27859243Sobrien size_t *oldlenp; 27959243Sobrien void *newp; 28059243Sobrien size_t newlen; 28159243Sobrien struct proc *p; 28259243Sobrien{ 28359243Sobrien extern char machine[], cpu_model[]; 28459243Sobrien 28559243Sobrien /* all sysctl names at this level are terminal */ 28659243Sobrien if (namelen != 1) 28759243Sobrien return (ENOTDIR); /* overloaded */ 28859243Sobrien 28959243Sobrien switch (name[0]) { 29059243Sobrien case HW_MACHINE: 29159243Sobrien return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 29259243Sobrien case HW_MODEL: 29359243Sobrien return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 294167465Smp case HW_NCPU: 29559243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 296167465Smp case HW_BYTEORDER: 297145479Smp return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 29859243Sobrien case HW_PHYSMEM: 29959243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 30059243Sobrien case HW_USERMEM: 30159243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, 30259243Sobrien ctob(physmem - cnt.v_wire_count))); 30359243Sobrien case HW_PAGESIZE: 30459243Sobrien return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 30559243Sobrien default: 30659243Sobrien return (EOPNOTSUPP); 30759243Sobrien } 30859243Sobrien /* NOTREACHED */ 30959243Sobrien} 31059243Sobrien 31159243Sobrien#ifdef DEBUG 31259243Sobrien/* 31359243Sobrien * Debugging related system variables. 31459243Sobrien */ 31559243Sobrienstruct ctldebug debug0, debug1, debug2, debug3, debug4; 316167465Smpstruct ctldebug debug5, debug6, debug7, debug8, debug9; 31759243Sobrienstruct ctldebug debug10, debug11, debug12, debug13, debug14; 31859243Sobrienstruct ctldebug debug15, debug16, debug17, debug18, debug19; 31959243Sobrienstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 32059243Sobrien &debug0, &debug1, &debug2, &debug3, &debug4, 32159243Sobrien &debug5, &debug6, &debug7, &debug8, &debug9, 32259243Sobrien &debug10, &debug11, &debug12, &debug13, &debug14, 32359243Sobrien &debug15, &debug16, &debug17, &debug18, &debug19, 32459243Sobrien}; 32559243Sobrienint 32659243Sobriendebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 32759243Sobrien int *name; 32859243Sobrien u_int namelen; 32959243Sobrien void *oldp; 33059243Sobrien size_t *oldlenp; 33159243Sobrien void *newp; 33259243Sobrien size_t newlen; 33359243Sobrien struct proc *p; 33459243Sobrien{ 33559243Sobrien struct ctldebug *cdp; 336167465Smp 33759243Sobrien /* all sysctl names at this level are name and field */ 338167465Smp if (namelen != 2) 339145479Smp return (ENOTDIR); /* overloaded */ 340145479Smp cdp = debugvars[name[0]]; 34159243Sobrien if (cdp->debugname == 0) 34259243Sobrien return (EOPNOTSUPP); 34359243Sobrien switch (name[1]) { 34459243Sobrien case CTL_DEBUG_NAME: 34559243Sobrien return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 34659243Sobrien case CTL_DEBUG_VALUE: 34759243Sobrien return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 34859243Sobrien default: 34959243Sobrien return (EOPNOTSUPP); 35059243Sobrien } 35159243Sobrien /* NOTREACHED */ 35259243Sobrien} 35359243Sobrien#endif /* DEBUG */ 35459243Sobrien 35559243Sobrien/* 35659243Sobrien * Validate parameters and get old / set new parameters 357167465Smp * for an integer-valued sysctl function. 35859243Sobrien */ 35959243Sobriensysctl_int(oldp, oldlenp, newp, newlen, valp) 36059243Sobrien void *oldp; 36159243Sobrien size_t *oldlenp; 36259243Sobrien void *newp; 36359243Sobrien size_t newlen; 36459243Sobrien int *valp; 36559243Sobrien{ 36659243Sobrien int error = 0; 36759243Sobrien 36859243Sobrien if (oldp && *oldlenp < sizeof(int)) 36959243Sobrien return (ENOMEM); 37059243Sobrien if (newp && newlen != sizeof(int)) 37159243Sobrien return (EINVAL); 37259243Sobrien *oldlenp = sizeof(int); 37359243Sobrien if (oldp) 37459243Sobrien error = copyout(valp, oldp, sizeof(int)); 37559243Sobrien if (error == 0 && newp) 37659243Sobrien error = copyin(newp, valp, sizeof(int)); 37759243Sobrien return (error); 378167465Smp} 37959243Sobrien 380167465Smp/* 381145479Smp * As above, but read-only. 382145479Smp */ 38359243Sobriensysctl_rdint(oldp, oldlenp, newp, val) 38459243Sobrien void *oldp; 38559243Sobrien size_t *oldlenp; 38659243Sobrien void *newp; 38759243Sobrien int val; 38859243Sobrien{ 38959243Sobrien int error = 0; 39059243Sobrien 39159243Sobrien if (oldp && *oldlenp < sizeof(int)) 39259243Sobrien return (ENOMEM); 39359243Sobrien if (newp) 39459243Sobrien return (EPERM); 39559243Sobrien *oldlenp = sizeof(int); 39659243Sobrien if (oldp) 397167465Smp error = copyout((caddr_t)&val, oldp, sizeof(int)); 39859243Sobrien return (error); 39959243Sobrien} 40059243Sobrien 40159243Sobrien/* 40259243Sobrien * Validate parameters and get old / set new parameters 40359243Sobrien * for a string-valued sysctl function. 40459243Sobrien */ 40559243Sobriensysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 40659243Sobrien void *oldp; 40759243Sobrien size_t *oldlenp; 40859243Sobrien void *newp; 40959243Sobrien size_t newlen; 41059243Sobrien char *str; 41159243Sobrien int maxlen; 41259243Sobrien{ 41359243Sobrien int len, error = 0; 41459243Sobrien 41559243Sobrien len = strlen(str) + 1; 41659243Sobrien if (oldp && *oldlenp < len) 41759243Sobrien return (ENOMEM); 41859243Sobrien if (newp && newlen >= maxlen) 419167465Smp return (EINVAL); 42059243Sobrien if (oldp) { 421167465Smp *oldlenp = len; 422145479Smp error = copyout(str, oldp, len); 423145479Smp } 42459243Sobrien if (error == 0 && newp) { 42559243Sobrien error = copyin(newp, str, newlen); 42659243Sobrien str[newlen] = 0; 42759243Sobrien } 42859243Sobrien return (error); 42959243Sobrien} 43059243Sobrien 43159243Sobrien/* 43259243Sobrien * As above, but read-only. 43359243Sobrien */ 43459243Sobriensysctl_rdstring(oldp, oldlenp, newp, str) 43559243Sobrien void *oldp; 43659243Sobrien size_t *oldlenp; 43759243Sobrien void *newp; 43859243Sobrien char *str; 43959243Sobrien{ 440167465Smp int len, error = 0; 44159243Sobrien 44259243Sobrien len = strlen(str) + 1; 44359243Sobrien if (oldp && *oldlenp < len) 44459243Sobrien return (ENOMEM); 44559243Sobrien if (newp) 44659243Sobrien return (EPERM); 44759243Sobrien *oldlenp = len; 44859243Sobrien if (oldp) 44959243Sobrien error = copyout(str, oldp, len); 45059243Sobrien return (error); 45159243Sobrien} 45259243Sobrien 45359243Sobrien/* 45459243Sobrien * Validate parameters and get old / set new parameters 45559243Sobrien * for a structure oriented sysctl function. 45659243Sobrien */ 45759243Sobriensysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 45859243Sobrien void *oldp; 45959243Sobrien size_t *oldlenp; 460167465Smp void *newp; 46159243Sobrien size_t newlen; 46259243Sobrien void *sp; 46359243Sobrien int len; 46459243Sobrien{ 46559243Sobrien int error = 0; 46659243Sobrien 46759243Sobrien if (oldp && *oldlenp < len) 46859243Sobrien return (ENOMEM); 46959243Sobrien if (newp && newlen > len) 47059243Sobrien return (EINVAL); 471167465Smp if (oldp) { 47259243Sobrien *oldlenp = len; 473167465Smp error = copyout(sp, oldp, len); 474167465Smp } 475145479Smp if (error == 0 && newp) 476145479Smp error = copyin(newp, sp, len); 47759243Sobrien return (error); 47859243Sobrien} 479145479Smp 48059243Sobrien/* 48159243Sobrien * Validate parameters and get old parameters 48259243Sobrien * for a structure oriented sysctl function. 48359243Sobrien */ 48459243Sobriensysctl_rdstruct(oldp, oldlenp, newp, sp, len) 48559243Sobrien void *oldp; 48659243Sobrien size_t *oldlenp; 48759243Sobrien void *newp, *sp; 48859243Sobrien int len; 48959243Sobrien{ 49059243Sobrien int error = 0; 49159243Sobrien 49259243Sobrien if (oldp && *oldlenp < len) 49359243Sobrien return (ENOMEM); 49459243Sobrien if (newp) 49559243Sobrien return (EPERM); 49659243Sobrien *oldlenp = len; 49759243Sobrien if (oldp) 49859243Sobrien error = copyout(sp, oldp, len); 49959243Sobrien return (error); 50059243Sobrien} 50159243Sobrien 50259243Sobrien/* 50359243Sobrien * Get file structures. 50459243Sobrien */ 50559243Sobriensysctl_file(where, sizep) 50659243Sobrien char *where; 50759243Sobrien size_t *sizep; 50859243Sobrien{ 50959243Sobrien int buflen, error; 51059243Sobrien struct file *fp; 51159243Sobrien char *start = where; 51259243Sobrien 51359243Sobrien buflen = *sizep; 51459243Sobrien if (where == NULL) { 51559243Sobrien /* 51659243Sobrien * overestimate by 10 files 51759243Sobrien */ 51859243Sobrien *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 51959243Sobrien return (0); 52059243Sobrien } 52159243Sobrien 52259243Sobrien /* 52359243Sobrien * first copyout filehead 52459243Sobrien */ 52559243Sobrien if (buflen < sizeof(filehead)) { 52659243Sobrien *sizep = 0; 52759243Sobrien return (0); 52859243Sobrien } 52959243Sobrien if (error = copyout((caddr_t)&filehead, where, sizeof(filehead))) 53059243Sobrien return (error); 53159243Sobrien buflen -= sizeof(filehead); 53259243Sobrien where += sizeof(filehead); 53359243Sobrien 53459243Sobrien /* 53559243Sobrien * followed by an array of file structures 53659243Sobrien */ 53759243Sobrien for (fp = filehead; fp != NULL; fp = fp->f_filef) { 53859243Sobrien if (buflen < sizeof(struct file)) { 53959243Sobrien *sizep = where - start; 54059243Sobrien return (ENOMEM); 54159243Sobrien } 54259243Sobrien if (error = copyout((caddr_t)fp, where, sizeof (struct file))) 54359243Sobrien return (error); 544167465Smp buflen -= sizeof(struct file); 545167465Smp where += sizeof(struct file); 54659243Sobrien } 54759243Sobrien *sizep = where - start; 54859243Sobrien return (0); 54959243Sobrien} 55059243Sobrien 55159243Sobrien/* 55259243Sobrien * try over estimating by 5 procs 55359243Sobrien */ 55459243Sobrien#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 55559243Sobrien 55659243Sobriensysctl_doproc(name, namelen, where, sizep) 55759243Sobrien int *name; 55859243Sobrien u_int namelen; 55959243Sobrien char *where; 56059243Sobrien size_t *sizep; 56159243Sobrien{ 56259243Sobrien register struct proc *p; 56359243Sobrien register struct kinfo_proc *dp = (struct kinfo_proc *)where; 56459243Sobrien register int needed = 0; 56559243Sobrien int buflen = where != NULL ? *sizep : 0; 56659243Sobrien int doingzomb; 56759243Sobrien struct eproc eproc; 56859243Sobrien int error = 0; 56959243Sobrien 57059243Sobrien if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 57159243Sobrien return (EINVAL); 57259243Sobrien p = (struct proc *)allproc; 57359243Sobrien doingzomb = 0; 57459243Sobrienagain: 57559243Sobrien for (; p != NULL; p = p->p_next) { 57659243Sobrien /* 57759243Sobrien * Skip embryonic processes. 57859243Sobrien */ 57959243Sobrien if (p->p_stat == SIDL) 58059243Sobrien continue; 58159243Sobrien /* 58259243Sobrien * TODO - make more efficient (see notes below). 58359243Sobrien * do by session. 58459243Sobrien */ 58559243Sobrien switch (name[0]) { 58659243Sobrien 58759243Sobrien case KERN_PROC_PID: 58859243Sobrien /* could do this with just a lookup */ 58959243Sobrien if (p->p_pid != (pid_t)name[1]) 59059243Sobrien continue; 59159243Sobrien break; 59259243Sobrien 59359243Sobrien case KERN_PROC_PGRP: 59459243Sobrien /* could do this by traversing pgrp */ 59559243Sobrien if (p->p_pgrp->pg_id != (pid_t)name[1]) 59659243Sobrien continue; 59759243Sobrien break; 59859243Sobrien 59959243Sobrien case KERN_PROC_TTY: 60059243Sobrien if ((p->p_flag & P_CONTROLT) == 0 || 60159243Sobrien p->p_session->s_ttyp == NULL || 60259243Sobrien p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 60359243Sobrien continue; 60459243Sobrien break; 60559243Sobrien 60659243Sobrien case KERN_PROC_UID: 60759243Sobrien if (p->p_ucred->cr_uid != (uid_t)name[1]) 60859243Sobrien continue; 60959243Sobrien break; 61059243Sobrien 61159243Sobrien case KERN_PROC_RUID: 61259243Sobrien if (p->p_cred->p_ruid != (uid_t)name[1]) 61359243Sobrien continue; 61459243Sobrien break; 61559243Sobrien } 61659243Sobrien if (buflen >= sizeof(struct kinfo_proc)) { 61759243Sobrien fill_eproc(p, &eproc); 61859243Sobrien if (error = copyout((caddr_t)p, &dp->kp_proc, 61959243Sobrien sizeof(struct proc))) 62059243Sobrien return (error); 62159243Sobrien if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 62259243Sobrien sizeof(eproc))) 62359243Sobrien return (error); 62459243Sobrien dp++; 62559243Sobrien buflen -= sizeof(struct kinfo_proc); 62659243Sobrien } 62759243Sobrien needed += sizeof(struct kinfo_proc); 62859243Sobrien } 62959243Sobrien if (doingzomb == 0) { 63059243Sobrien p = zombproc; 63159243Sobrien doingzomb++; 63259243Sobrien goto again; 63359243Sobrien } 63459243Sobrien if (where != NULL) { 63559243Sobrien *sizep = (caddr_t)dp - where; 63659243Sobrien if (needed > *sizep) 63759243Sobrien return (ENOMEM); 63859243Sobrien } else { 63959243Sobrien needed += KERN_PROCSLOP; 64059243Sobrien *sizep = needed; 64159243Sobrien } 64259243Sobrien return (0); 64359243Sobrien} 64459243Sobrien 64559243Sobrien/* 64659243Sobrien * Fill in an eproc structure for the specified process. 64759243Sobrien */ 64859243Sobrienvoid 64959243Sobrienfill_eproc(p, ep) 650167465Smp register struct proc *p; 65159243Sobrien register struct eproc *ep; 652145479Smp{ 65359243Sobrien register struct tty *tp; 65459243Sobrien 65559243Sobrien ep->e_paddr = p; 65659243Sobrien ep->e_sess = p->p_pgrp->pg_session; 65759243Sobrien ep->e_pcred = *p->p_cred; 65859243Sobrien ep->e_ucred = *p->p_ucred; 65959243Sobrien if (p->p_stat == SIDL || p->p_stat == SZOMB) { 660167465Smp ep->e_vm.vm_rssize = 0; 661167465Smp ep->e_vm.vm_tsize = 0; 662167465Smp ep->e_vm.vm_dsize = 0; 663167465Smp ep->e_vm.vm_ssize = 0; 66459243Sobrien#ifndef sparc 66559243Sobrien /* ep->e_vm.vm_pmap = XXX; */ 66659243Sobrien#endif 667167465Smp } else { 668167465Smp register struct vmspace *vm = p->p_vmspace; 66959243Sobrien 67059243Sobrien#ifdef pmap_resident_count 67159243Sobrien ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/ 67259243Sobrien#else 67359243Sobrien ep->e_vm.vm_rssize = vm->vm_rssize; 67459243Sobrien#endif 67559243Sobrien ep->e_vm.vm_tsize = vm->vm_tsize; 67659243Sobrien ep->e_vm.vm_dsize = vm->vm_dsize; 67759243Sobrien ep->e_vm.vm_ssize = vm->vm_ssize; 67859243Sobrien#ifndef sparc 67959243Sobrien ep->e_vm.vm_pmap = vm->vm_pmap; 680231990Smp#endif 681231990Smp } 682231990Smp if (p->p_pptr) 683167465Smp ep->e_ppid = p->p_pptr->p_pid; 68459243Sobrien else 685167465Smp ep->e_ppid = 0; 686167465Smp ep->e_pgid = p->p_pgrp->pg_id; 687167465Smp ep->e_jobc = p->p_pgrp->pg_jobc; 688167465Smp if ((p->p_flag & P_CONTROLT) && 689167465Smp (tp = ep->e_sess->s_ttyp)) { 690167465Smp ep->e_tdev = tp->t_dev; 691167465Smp ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 692167465Smp ep->e_tsess = tp->t_session; 693167465Smp } else 694 ep->e_tdev = NODEV; 695 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 696 if (SESS_LEADER(p)) 697 ep->e_flag |= EPROC_SLEADER; 698 if (p->p_wmesg) 699 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 700 ep->e_xsize = ep->e_xrssize = 0; 701 ep->e_xccount = ep->e_xswrss = 0; 702} 703 704#ifdef COMPAT_43 705#include <sys/socket.h> 706#define KINFO_PROC (0<<8) 707#define KINFO_RT (1<<8) 708#define KINFO_VNODE (2<<8) 709#define KINFO_FILE (3<<8) 710#define KINFO_METER (4<<8) 711#define KINFO_LOADAVG (5<<8) 712#define KINFO_CLOCKRATE (6<<8) 713 714struct getkerninfo_args { 715 int op; 716 char *where; 717 int *size; 718 int arg; 719}; 720 721ogetkerninfo(p, uap, retval) 722 struct proc *p; 723 register struct getkerninfo_args *uap; 724 int *retval; 725{ 726 int error, name[5]; 727 u_int size; 728 729 if (uap->size && 730 (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size)))) 731 return (error); 732 733 switch (uap->op & 0xff00) { 734 735 case KINFO_RT: 736 name[0] = PF_ROUTE; 737 name[1] = 0; 738 name[2] = (uap->op & 0xff0000) >> 16; 739 name[3] = uap->op & 0xff; 740 name[4] = uap->arg; 741 error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p); 742 break; 743 744 case KINFO_VNODE: 745 name[0] = KERN_VNODE; 746 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 747 break; 748 749 case KINFO_PROC: 750 name[0] = KERN_PROC; 751 name[1] = uap->op & 0xff; 752 name[2] = uap->arg; 753 error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p); 754 break; 755 756 case KINFO_FILE: 757 name[0] = KERN_FILE; 758 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 759 break; 760 761 case KINFO_METER: 762 name[0] = VM_METER; 763 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 764 break; 765 766 case KINFO_LOADAVG: 767 name[0] = VM_LOADAVG; 768 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 769 break; 770 771 case KINFO_CLOCKRATE: 772 name[0] = KERN_CLOCKRATE; 773 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 774 break; 775 776 default: 777 return (EOPNOTSUPP); 778 } 779 if (error) 780 return (error); 781 *retval = size; 782 if (uap->size) 783 error = copyout((caddr_t)&size, (caddr_t)uap->size, 784 sizeof(size)); 785 return (error); 786} 787#endif /* COMPAT_43 */ 788