kern_sysctl.c revision 3308
11541Srgrimes/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Mike Karels at Berkeley Software Design, Inc. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 3. All advertising materials mentioning features or use of this software 171541Srgrimes * must display the following acknowledgement: 181541Srgrimes * This product includes software developed by the University of 191541Srgrimes * California, Berkeley and its contributors. 201541Srgrimes * 4. Neither the name of the University nor the names of its contributors 211541Srgrimes * may be used to endorse or promote products derived from this software 221541Srgrimes * without specific prior written permission. 231541Srgrimes * 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341541Srgrimes * SUCH DAMAGE. 351541Srgrimes * 361541Srgrimes * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 373308Sphk * $Id: kern_sysctl.c,v 1.15 1994/09/23 19:07:17 wollman Exp $ 381541Srgrimes */ 391541Srgrimes 401541Srgrimes/* 411541Srgrimes * sysctl system call. 421541Srgrimes */ 431541Srgrimes 441541Srgrimes#include <sys/param.h> 451541Srgrimes#include <sys/systm.h> 461541Srgrimes#include <sys/kernel.h> 471541Srgrimes#include <sys/malloc.h> 481541Srgrimes#include <sys/proc.h> 491541Srgrimes#include <sys/file.h> 501541Srgrimes#include <sys/vnode.h> 511541Srgrimes#include <sys/unistd.h> 521541Srgrimes#include <sys/buf.h> 531541Srgrimes#include <sys/ioctl.h> 541541Srgrimes#include <sys/tty.h> 551541Srgrimes#include <vm/vm.h> 561541Srgrimes#include <sys/sysctl.h> 571541Srgrimes 581541Srgrimessysctlfn kern_sysctl; 591541Srgrimessysctlfn hw_sysctl; 601541Srgrimes#ifdef DEBUG 611541Srgrimessysctlfn debug_sysctl; 621541Srgrimes#endif 631541Srgrimesextern sysctlfn vm_sysctl; 641541Srgrimesextern sysctlfn fs_sysctl; 651541Srgrimesextern sysctlfn net_sysctl; 661541Srgrimesextern sysctlfn cpu_sysctl; 672858Swollmanextern sysctlfn ntp_sysctl; 681541Srgrimes 691541Srgrimes/* 701541Srgrimes * Locking and stats 711541Srgrimes */ 721541Srgrimesstatic struct sysctl_lock { 731541Srgrimes int sl_lock; 741541Srgrimes int sl_want; 751541Srgrimes int sl_locked; 761541Srgrimes} memlock; 771541Srgrimes 781541Srgrimesstruct sysctl_args { 791541Srgrimes int *name; 801541Srgrimes u_int namelen; 811541Srgrimes void *old; 821541Srgrimes size_t *oldlenp; 831541Srgrimes void *new; 841541Srgrimes size_t newlen; 851541Srgrimes}; 861541Srgrimes 871541Srgrimesint 881541Srgrimes__sysctl(p, uap, retval) 891541Srgrimes struct proc *p; 901541Srgrimes register struct sysctl_args *uap; 911541Srgrimes int *retval; 921541Srgrimes{ 931541Srgrimes int error, dolock = 1; 941549Srgrimes u_int savelen = 0, oldlen = 0; 951541Srgrimes sysctlfn *fn; 961541Srgrimes int name[CTL_MAXNAME]; 971541Srgrimes 981541Srgrimes if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 991541Srgrimes return (error); 1001541Srgrimes /* 1011541Srgrimes * all top-level sysctl names are non-terminal 1021541Srgrimes */ 1031541Srgrimes if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 1041541Srgrimes return (EINVAL); 1053308Sphk error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 1063308Sphk if (error) 1071541Srgrimes return (error); 1081541Srgrimes 1091541Srgrimes switch (name[0]) { 1101541Srgrimes case CTL_KERN: 1111541Srgrimes fn = kern_sysctl; 1122903Sache if (name[1] != KERN_VNODE) /* XXX */ 1131541Srgrimes dolock = 0; 1141541Srgrimes break; 1151541Srgrimes case CTL_HW: 1161541Srgrimes fn = hw_sysctl; 1171541Srgrimes break; 1181541Srgrimes case CTL_VM: 1191541Srgrimes fn = vm_sysctl; 1201541Srgrimes break; 1211541Srgrimes case CTL_NET: 1221541Srgrimes fn = net_sysctl; 1231541Srgrimes break; 1241541Srgrimes case CTL_FS: 1251541Srgrimes fn = fs_sysctl; 1261541Srgrimes break; 1271541Srgrimes case CTL_MACHDEP: 1281541Srgrimes fn = cpu_sysctl; 1291541Srgrimes break; 1301541Srgrimes#ifdef DEBUG 1311541Srgrimes case CTL_DEBUG: 1321541Srgrimes fn = debug_sysctl; 1331541Srgrimes break; 1341541Srgrimes#endif 1351541Srgrimes default: 1361541Srgrimes return (EOPNOTSUPP); 1371541Srgrimes } 1381541Srgrimes 1391541Srgrimes if (uap->oldlenp && 1401541Srgrimes (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen)))) 1411541Srgrimes return (error); 1421541Srgrimes if (uap->old != NULL) { 1431541Srgrimes if (!useracc(uap->old, oldlen, B_WRITE)) 1441541Srgrimes return (EFAULT); 1451541Srgrimes while (memlock.sl_lock) { 1461541Srgrimes memlock.sl_want = 1; 1471541Srgrimes sleep((caddr_t)&memlock, PRIBIO+1); 1481541Srgrimes memlock.sl_locked++; 1491541Srgrimes } 1501541Srgrimes memlock.sl_lock = 1; 1511541Srgrimes if (dolock) 1521541Srgrimes vslock(uap->old, oldlen); 1531541Srgrimes savelen = oldlen; 1541541Srgrimes } 1551541Srgrimes error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen, 1561541Srgrimes uap->new, uap->newlen, p); 1571541Srgrimes if (uap->old != NULL) { 1581541Srgrimes if (dolock) 1591541Srgrimes vsunlock(uap->old, savelen, B_WRITE); 1601541Srgrimes memlock.sl_lock = 0; 1611541Srgrimes if (memlock.sl_want) { 1621541Srgrimes memlock.sl_want = 0; 1631541Srgrimes wakeup((caddr_t)&memlock); 1641541Srgrimes } 1651541Srgrimes } 1661541Srgrimes if (error) 1671541Srgrimes return (error); 1681541Srgrimes if (uap->oldlenp) 1691541Srgrimes error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen)); 1701541Srgrimes *retval = oldlen; 1711541Srgrimes return (0); 1721541Srgrimes} 1731541Srgrimes 1741541Srgrimes/* 1751541Srgrimes * Attributes stored in the kernel. 1761541Srgrimes */ 1771541Srgrimeschar hostname[MAXHOSTNAMELEN]; 1781541Srgrimesint hostnamelen; 1791925Swollmanchar domainname[MAXHOSTNAMELEN]; 1801925Swollmanint domainnamelen; 1811541Srgrimeslong hostid; 1821995Swollmanint securelevel = -1; 1833038Swollmanchar kernelname[MAXPATHLEN] = "/kernel"; 1841952Swollmanextern int vfs_update_wakeup; 1851952Swollmanextern int vfs_update_interval; 1862004Swollmanextern int osreldate; 1871541Srgrimes 1881541Srgrimes/* 1891541Srgrimes * kernel related system variables. 1901541Srgrimes */ 1911549Srgrimesint 1921541Srgrimeskern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 1931541Srgrimes int *name; 1941541Srgrimes u_int namelen; 1951541Srgrimes void *oldp; 1961541Srgrimes size_t *oldlenp; 1971541Srgrimes void *newp; 1981541Srgrimes size_t newlen; 1991541Srgrimes struct proc *p; 2001541Srgrimes{ 2011541Srgrimes int error, level, inthostid; 2022112Swollman extern char ostype[], osrelease[]; 2031541Srgrimes 2041541Srgrimes /* all sysctl names at this level are terminal */ 2052858Swollman if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF 2062858Swollman || name[0] == KERN_NTP_PLL)) 2071541Srgrimes return (ENOTDIR); /* overloaded */ 2081541Srgrimes 2091541Srgrimes switch (name[0]) { 2101541Srgrimes case KERN_OSTYPE: 2111541Srgrimes return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 2121541Srgrimes case KERN_OSRELEASE: 2131541Srgrimes return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 2141541Srgrimes case KERN_OSREV: 2151541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, BSD)); 2161541Srgrimes case KERN_VERSION: 2171541Srgrimes return (sysctl_rdstring(oldp, oldlenp, newp, version)); 2182004Swollman case KERN_OSRELDATE: 2192004Swollman return (sysctl_rdint(oldp, oldlenp, newp, osreldate)); 2203038Swollman case KERN_BOOTFILE: 2213038Swollman return (sysctl_string(oldp, oldlenp, newp, newlen, 2223038Swollman kernelname, sizeof kernelname)); 2231541Srgrimes case KERN_MAXVNODES: 2241541Srgrimes return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes)); 2251541Srgrimes case KERN_MAXPROC: 2261541Srgrimes return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 2271541Srgrimes case KERN_MAXFILES: 2281541Srgrimes return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 2291952Swollman case KERN_UPDATEINTERVAL: 2301952Swollman /* 2311952Swollman * NB: this simple-minded approach only works because 2321952Swollman * `tsleep' takes a timeout argument of 0 as meaning 2331952Swollman * `no timeout'. 2341952Swollman */ 2351952Swollman error = sysctl_int(oldp, oldlenp, newp, newlen, 2361952Swollman &vfs_update_interval); 2371952Swollman if(!error) { 2381952Swollman wakeup(&vfs_update_wakeup); 2391952Swollman } 2401952Swollman return error; 2411541Srgrimes case KERN_ARGMAX: 2421541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 2431541Srgrimes case KERN_SECURELVL: 2441541Srgrimes level = securelevel; 2451541Srgrimes if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 2461541Srgrimes newp == NULL) 2471541Srgrimes return (error); 2481541Srgrimes if (level < securelevel && p->p_pid != 1) 2491541Srgrimes return (EPERM); 2501541Srgrimes securelevel = level; 2511541Srgrimes return (0); 2521541Srgrimes case KERN_HOSTNAME: 2531541Srgrimes error = sysctl_string(oldp, oldlenp, newp, newlen, 2541541Srgrimes hostname, sizeof(hostname)); 2551541Srgrimes if (newp && !error) 2561541Srgrimes hostnamelen = newlen; 2571541Srgrimes return (error); 2581925Swollman case KERN_DOMAINNAME: 2591925Swollman error = sysctl_string(oldp, oldlenp, newp, newlen, 2601925Swollman domainname, sizeof(domainname)); 2611925Swollman if (newp && !error) 2621925Swollman domainnamelen = newlen; 2631925Swollman return (error); 2641541Srgrimes case KERN_HOSTID: 2651541Srgrimes inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 2661541Srgrimes error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 2671541Srgrimes hostid = inthostid; 2681541Srgrimes return (error); 2691541Srgrimes case KERN_CLOCKRATE: 2701541Srgrimes return (sysctl_clockrate(oldp, oldlenp)); 2711541Srgrimes case KERN_BOOTTIME: 2721541Srgrimes return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 2731541Srgrimes sizeof(struct timeval))); 2741541Srgrimes case KERN_VNODE: 2751541Srgrimes return (sysctl_vnode(oldp, oldlenp)); 2761541Srgrimes case KERN_PROC: 2771541Srgrimes return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 2781541Srgrimes case KERN_FILE: 2791541Srgrimes return (sysctl_file(oldp, oldlenp)); 2801541Srgrimes#ifdef GPROF 2811541Srgrimes case KERN_PROF: 2821541Srgrimes return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 2831541Srgrimes newp, newlen)); 2841541Srgrimes#endif 2851541Srgrimes case KERN_POSIX1: 2861541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 2871541Srgrimes case KERN_NGROUPS: 2881541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 2891541Srgrimes case KERN_JOB_CONTROL: 2901541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, 1)); 2911541Srgrimes case KERN_SAVED_IDS: 2921541Srgrimes#ifdef _POSIX_SAVED_IDS 2931541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, 1)); 2941541Srgrimes#else 2951541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, 0)); 2961541Srgrimes#endif 2972858Swollman case KERN_NTP_PLL: 2982858Swollman return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp, 2992858Swollman newp, newlen, p)); 3001541Srgrimes default: 3011541Srgrimes return (EOPNOTSUPP); 3021541Srgrimes } 3031541Srgrimes /* NOTREACHED */ 3041541Srgrimes} 3051541Srgrimes 3061541Srgrimes/* 3071541Srgrimes * hardware related system variables. 3081541Srgrimes */ 3091549Srgrimesint 3101541Srgrimeshw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 3111541Srgrimes int *name; 3121541Srgrimes u_int namelen; 3131541Srgrimes void *oldp; 3141541Srgrimes size_t *oldlenp; 3151541Srgrimes void *newp; 3161541Srgrimes size_t newlen; 3171541Srgrimes struct proc *p; 3181541Srgrimes{ 3191541Srgrimes extern char machine[], cpu_model[]; 3202631Swollman extern int hw_float; 3211541Srgrimes 3221541Srgrimes /* all sysctl names at this level are terminal */ 3231541Srgrimes if (namelen != 1) 3241541Srgrimes return (ENOTDIR); /* overloaded */ 3251541Srgrimes 3261541Srgrimes switch (name[0]) { 3271541Srgrimes case HW_MACHINE: 3281541Srgrimes return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 3291541Srgrimes case HW_MODEL: 3301541Srgrimes return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 3311541Srgrimes case HW_NCPU: 3321541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 3331541Srgrimes case HW_BYTEORDER: 3341541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 3351541Srgrimes case HW_PHYSMEM: 3361541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 3371541Srgrimes case HW_USERMEM: 3381541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, 3391541Srgrimes ctob(physmem - cnt.v_wire_count))); 3401541Srgrimes case HW_PAGESIZE: 3411541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 3422631Swollman case HW_FLOATINGPT: 3432631Swollman return (sysctl_rdint(oldp, oldlenp, newp, hw_float)); 3441541Srgrimes default: 3451541Srgrimes return (EOPNOTSUPP); 3461541Srgrimes } 3471541Srgrimes /* NOTREACHED */ 3481541Srgrimes} 3491541Srgrimes 3501541Srgrimes#ifdef DEBUG 3511541Srgrimes/* 3521541Srgrimes * Debugging related system variables. 3531541Srgrimes */ 3541541Srgrimesstruct ctldebug debug0, debug1, debug2, debug3, debug4; 3551541Srgrimesstruct ctldebug debug5, debug6, debug7, debug8, debug9; 3561541Srgrimesstruct ctldebug debug10, debug11, debug12, debug13, debug14; 3571541Srgrimesstruct ctldebug debug15, debug16, debug17, debug18, debug19; 3581541Srgrimesstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 3591541Srgrimes &debug0, &debug1, &debug2, &debug3, &debug4, 3601541Srgrimes &debug5, &debug6, &debug7, &debug8, &debug9, 3611541Srgrimes &debug10, &debug11, &debug12, &debug13, &debug14, 3621541Srgrimes &debug15, &debug16, &debug17, &debug18, &debug19, 3631541Srgrimes}; 3641541Srgrimesint 3651541Srgrimesdebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 3661541Srgrimes int *name; 3671541Srgrimes u_int namelen; 3681541Srgrimes void *oldp; 3691541Srgrimes size_t *oldlenp; 3701541Srgrimes void *newp; 3711541Srgrimes size_t newlen; 3721541Srgrimes struct proc *p; 3731541Srgrimes{ 3741541Srgrimes struct ctldebug *cdp; 3751541Srgrimes 3761541Srgrimes /* all sysctl names at this level are name and field */ 3771541Srgrimes if (namelen != 2) 3781541Srgrimes return (ENOTDIR); /* overloaded */ 3791541Srgrimes cdp = debugvars[name[0]]; 3801541Srgrimes if (cdp->debugname == 0) 3811541Srgrimes return (EOPNOTSUPP); 3821541Srgrimes switch (name[1]) { 3831541Srgrimes case CTL_DEBUG_NAME: 3841541Srgrimes return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 3851541Srgrimes case CTL_DEBUG_VALUE: 3861541Srgrimes return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 3871541Srgrimes default: 3881541Srgrimes return (EOPNOTSUPP); 3891541Srgrimes } 3901541Srgrimes /* NOTREACHED */ 3911541Srgrimes} 3921541Srgrimes#endif /* DEBUG */ 3931541Srgrimes 3941541Srgrimes/* 3951541Srgrimes * Validate parameters and get old / set new parameters 3961541Srgrimes * for an integer-valued sysctl function. 3971541Srgrimes */ 3981549Srgrimesint 3991541Srgrimessysctl_int(oldp, oldlenp, newp, newlen, valp) 4001541Srgrimes void *oldp; 4011541Srgrimes size_t *oldlenp; 4021541Srgrimes void *newp; 4031541Srgrimes size_t newlen; 4041541Srgrimes int *valp; 4051541Srgrimes{ 4061541Srgrimes int error = 0; 4071541Srgrimes 4081541Srgrimes if (oldp && *oldlenp < sizeof(int)) 4091541Srgrimes return (ENOMEM); 4101541Srgrimes if (newp && newlen != sizeof(int)) 4111541Srgrimes return (EINVAL); 4121541Srgrimes *oldlenp = sizeof(int); 4131541Srgrimes if (oldp) 4141541Srgrimes error = copyout(valp, oldp, sizeof(int)); 4151541Srgrimes if (error == 0 && newp) 4161541Srgrimes error = copyin(newp, valp, sizeof(int)); 4171541Srgrimes return (error); 4181541Srgrimes} 4191541Srgrimes 4201541Srgrimes/* 4211541Srgrimes * As above, but read-only. 4221541Srgrimes */ 4231549Srgrimesint 4241541Srgrimessysctl_rdint(oldp, oldlenp, newp, val) 4251541Srgrimes void *oldp; 4261541Srgrimes size_t *oldlenp; 4271541Srgrimes void *newp; 4281541Srgrimes int val; 4291541Srgrimes{ 4301541Srgrimes int error = 0; 4311541Srgrimes 4321541Srgrimes if (oldp && *oldlenp < sizeof(int)) 4331541Srgrimes return (ENOMEM); 4341541Srgrimes if (newp) 4351541Srgrimes return (EPERM); 4361541Srgrimes *oldlenp = sizeof(int); 4371541Srgrimes if (oldp) 4381541Srgrimes error = copyout((caddr_t)&val, oldp, sizeof(int)); 4391541Srgrimes return (error); 4401541Srgrimes} 4411541Srgrimes 4421541Srgrimes/* 4431541Srgrimes * Validate parameters and get old / set new parameters 4441541Srgrimes * for a string-valued sysctl function. 4451541Srgrimes */ 4461549Srgrimesint 4471541Srgrimessysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 4481541Srgrimes void *oldp; 4491541Srgrimes size_t *oldlenp; 4501541Srgrimes void *newp; 4511541Srgrimes size_t newlen; 4521541Srgrimes char *str; 4531541Srgrimes int maxlen; 4541541Srgrimes{ 4551541Srgrimes int len, error = 0; 4561541Srgrimes 4571541Srgrimes len = strlen(str) + 1; 4581541Srgrimes if (oldp && *oldlenp < len) 4591541Srgrimes return (ENOMEM); 4601541Srgrimes if (newp && newlen >= maxlen) 4611541Srgrimes return (EINVAL); 4621541Srgrimes if (oldp) { 4631541Srgrimes *oldlenp = len; 4641541Srgrimes error = copyout(str, oldp, len); 4651541Srgrimes } 4661541Srgrimes if (error == 0 && newp) { 4671541Srgrimes error = copyin(newp, str, newlen); 4681541Srgrimes str[newlen] = 0; 4691541Srgrimes } 4701541Srgrimes return (error); 4711541Srgrimes} 4721541Srgrimes 4731541Srgrimes/* 4741541Srgrimes * As above, but read-only. 4751541Srgrimes */ 4761549Srgrimesint 4771541Srgrimessysctl_rdstring(oldp, oldlenp, newp, str) 4781541Srgrimes void *oldp; 4791541Srgrimes size_t *oldlenp; 4801541Srgrimes void *newp; 4811541Srgrimes char *str; 4821541Srgrimes{ 4831541Srgrimes int len, error = 0; 4841541Srgrimes 4851541Srgrimes len = strlen(str) + 1; 4861541Srgrimes if (oldp && *oldlenp < len) 4871541Srgrimes return (ENOMEM); 4881541Srgrimes if (newp) 4891541Srgrimes return (EPERM); 4901541Srgrimes *oldlenp = len; 4911541Srgrimes if (oldp) 4921541Srgrimes error = copyout(str, oldp, len); 4931541Srgrimes return (error); 4941541Srgrimes} 4951541Srgrimes 4961541Srgrimes/* 4971541Srgrimes * Validate parameters and get old / set new parameters 4981541Srgrimes * for a structure oriented sysctl function. 4991541Srgrimes */ 5001549Srgrimesint 5011541Srgrimessysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 5021541Srgrimes void *oldp; 5031541Srgrimes size_t *oldlenp; 5041541Srgrimes void *newp; 5051541Srgrimes size_t newlen; 5061541Srgrimes void *sp; 5071541Srgrimes int len; 5081541Srgrimes{ 5091541Srgrimes int error = 0; 5101541Srgrimes 5111541Srgrimes if (oldp && *oldlenp < len) 5121541Srgrimes return (ENOMEM); 5131541Srgrimes if (newp && newlen > len) 5141541Srgrimes return (EINVAL); 5151541Srgrimes if (oldp) { 5161541Srgrimes *oldlenp = len; 5171541Srgrimes error = copyout(sp, oldp, len); 5181541Srgrimes } 5191541Srgrimes if (error == 0 && newp) 5201541Srgrimes error = copyin(newp, sp, len); 5211541Srgrimes return (error); 5221541Srgrimes} 5231541Srgrimes 5241541Srgrimes/* 5251541Srgrimes * Validate parameters and get old parameters 5261541Srgrimes * for a structure oriented sysctl function. 5271541Srgrimes */ 5281549Srgrimesint 5291541Srgrimessysctl_rdstruct(oldp, oldlenp, newp, sp, len) 5301541Srgrimes void *oldp; 5311541Srgrimes size_t *oldlenp; 5321541Srgrimes void *newp, *sp; 5331541Srgrimes int len; 5341541Srgrimes{ 5351541Srgrimes int error = 0; 5361541Srgrimes 5371541Srgrimes if (oldp && *oldlenp < len) 5381541Srgrimes return (ENOMEM); 5391541Srgrimes if (newp) 5401541Srgrimes return (EPERM); 5411541Srgrimes *oldlenp = len; 5421541Srgrimes if (oldp) 5431541Srgrimes error = copyout(sp, oldp, len); 5441541Srgrimes return (error); 5451541Srgrimes} 5461541Srgrimes 5471541Srgrimes/* 5481541Srgrimes * Get file structures. 5491541Srgrimes */ 5501549Srgrimesint 5511541Srgrimessysctl_file(where, sizep) 5521541Srgrimes char *where; 5531541Srgrimes size_t *sizep; 5541541Srgrimes{ 5551541Srgrimes int buflen, error; 5561541Srgrimes struct file *fp; 5571541Srgrimes char *start = where; 5581541Srgrimes 5591541Srgrimes buflen = *sizep; 5601541Srgrimes if (where == NULL) { 5611541Srgrimes /* 5621541Srgrimes * overestimate by 10 files 5631541Srgrimes */ 5641541Srgrimes *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 5651541Srgrimes return (0); 5661541Srgrimes } 5671541Srgrimes 5681541Srgrimes /* 5691541Srgrimes * first copyout filehead 5701541Srgrimes */ 5711541Srgrimes if (buflen < sizeof(filehead)) { 5721541Srgrimes *sizep = 0; 5731541Srgrimes return (0); 5741541Srgrimes } 5753308Sphk error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 5763308Sphk if (error) 5771541Srgrimes return (error); 5781541Srgrimes buflen -= sizeof(filehead); 5791541Srgrimes where += sizeof(filehead); 5801541Srgrimes 5811541Srgrimes /* 5821541Srgrimes * followed by an array of file structures 5831541Srgrimes */ 5841541Srgrimes for (fp = filehead; fp != NULL; fp = fp->f_filef) { 5851541Srgrimes if (buflen < sizeof(struct file)) { 5861541Srgrimes *sizep = where - start; 5871541Srgrimes return (ENOMEM); 5881541Srgrimes } 5893308Sphk error = copyout((caddr_t)fp, where, sizeof (struct file)); 5903308Sphk if (error) 5911541Srgrimes return (error); 5921541Srgrimes buflen -= sizeof(struct file); 5931541Srgrimes where += sizeof(struct file); 5941541Srgrimes } 5951541Srgrimes *sizep = where - start; 5961541Srgrimes return (0); 5971541Srgrimes} 5981541Srgrimes 5991541Srgrimes/* 6001541Srgrimes * try over estimating by 5 procs 6011541Srgrimes */ 6021541Srgrimes#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 6031541Srgrimes 6041549Srgrimesint 6051541Srgrimessysctl_doproc(name, namelen, where, sizep) 6061541Srgrimes int *name; 6071541Srgrimes u_int namelen; 6081541Srgrimes char *where; 6091541Srgrimes size_t *sizep; 6101541Srgrimes{ 6111541Srgrimes register struct proc *p; 6121541Srgrimes register struct kinfo_proc *dp = (struct kinfo_proc *)where; 6131541Srgrimes register int needed = 0; 6141541Srgrimes int buflen = where != NULL ? *sizep : 0; 6151541Srgrimes int doingzomb; 6161541Srgrimes struct eproc eproc; 6171541Srgrimes int error = 0; 6181541Srgrimes 6191541Srgrimes if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 6201541Srgrimes return (EINVAL); 6211541Srgrimes p = (struct proc *)allproc; 6221541Srgrimes doingzomb = 0; 6231541Srgrimesagain: 6241541Srgrimes for (; p != NULL; p = p->p_next) { 6251541Srgrimes /* 6261541Srgrimes * Skip embryonic processes. 6271541Srgrimes */ 6281541Srgrimes if (p->p_stat == SIDL) 6291541Srgrimes continue; 6301541Srgrimes /* 6311541Srgrimes * TODO - make more efficient (see notes below). 6321541Srgrimes * do by session. 6331541Srgrimes */ 6341541Srgrimes switch (name[0]) { 6351541Srgrimes 6361541Srgrimes case KERN_PROC_PID: 6371541Srgrimes /* could do this with just a lookup */ 6381541Srgrimes if (p->p_pid != (pid_t)name[1]) 6391541Srgrimes continue; 6401541Srgrimes break; 6411541Srgrimes 6421541Srgrimes case KERN_PROC_PGRP: 6431541Srgrimes /* could do this by traversing pgrp */ 6441541Srgrimes if (p->p_pgrp->pg_id != (pid_t)name[1]) 6451541Srgrimes continue; 6461541Srgrimes break; 6471541Srgrimes 6481541Srgrimes case KERN_PROC_TTY: 6491541Srgrimes if ((p->p_flag & P_CONTROLT) == 0 || 6501541Srgrimes p->p_session->s_ttyp == NULL || 6511541Srgrimes p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 6521541Srgrimes continue; 6531541Srgrimes break; 6541541Srgrimes 6551541Srgrimes case KERN_PROC_UID: 6561541Srgrimes if (p->p_ucred->cr_uid != (uid_t)name[1]) 6571541Srgrimes continue; 6581541Srgrimes break; 6591541Srgrimes 6601541Srgrimes case KERN_PROC_RUID: 6611541Srgrimes if (p->p_cred->p_ruid != (uid_t)name[1]) 6621541Srgrimes continue; 6631541Srgrimes break; 6641541Srgrimes } 6651541Srgrimes if (buflen >= sizeof(struct kinfo_proc)) { 6661541Srgrimes fill_eproc(p, &eproc); 6673308Sphk error = copyout((caddr_t)p, &dp->kp_proc, 6683308Sphk sizeof(struct proc)); 6693308Sphk if (error) 6701541Srgrimes return (error); 6713308Sphk error = copyout((caddr_t)&eproc, &dp->kp_eproc, 6723308Sphk sizeof(eproc)); 6733308Sphk if (error) 6741541Srgrimes return (error); 6751541Srgrimes dp++; 6761541Srgrimes buflen -= sizeof(struct kinfo_proc); 6771541Srgrimes } 6781541Srgrimes needed += sizeof(struct kinfo_proc); 6791541Srgrimes } 6801541Srgrimes if (doingzomb == 0) { 6811541Srgrimes p = zombproc; 6821541Srgrimes doingzomb++; 6831541Srgrimes goto again; 6841541Srgrimes } 6851541Srgrimes if (where != NULL) { 6861541Srgrimes *sizep = (caddr_t)dp - where; 6871541Srgrimes if (needed > *sizep) 6881541Srgrimes return (ENOMEM); 6891541Srgrimes } else { 6901541Srgrimes needed += KERN_PROCSLOP; 6911541Srgrimes *sizep = needed; 6921541Srgrimes } 6931541Srgrimes return (0); 6941541Srgrimes} 6951541Srgrimes 6961541Srgrimes/* 6971541Srgrimes * Fill in an eproc structure for the specified process. 6981541Srgrimes */ 6991541Srgrimesvoid 7001541Srgrimesfill_eproc(p, ep) 7011541Srgrimes register struct proc *p; 7021541Srgrimes register struct eproc *ep; 7031541Srgrimes{ 7041541Srgrimes register struct tty *tp; 7051541Srgrimes 7061541Srgrimes ep->e_paddr = p; 7071541Srgrimes ep->e_sess = p->p_pgrp->pg_session; 7081541Srgrimes ep->e_pcred = *p->p_cred; 7091541Srgrimes ep->e_ucred = *p->p_ucred; 7101541Srgrimes if (p->p_stat == SIDL || p->p_stat == SZOMB) { 7111541Srgrimes ep->e_vm.vm_rssize = 0; 7121541Srgrimes ep->e_vm.vm_tsize = 0; 7131541Srgrimes ep->e_vm.vm_dsize = 0; 7141541Srgrimes ep->e_vm.vm_ssize = 0; 7151541Srgrimes#ifndef sparc 7161541Srgrimes /* ep->e_vm.vm_pmap = XXX; */ 7171541Srgrimes#endif 7181541Srgrimes } else { 7191541Srgrimes register struct vmspace *vm = p->p_vmspace; 7201541Srgrimes 7211541Srgrimes#ifdef pmap_resident_count 7221541Srgrimes ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/ 7231541Srgrimes#else 7241541Srgrimes ep->e_vm.vm_rssize = vm->vm_rssize; 7251541Srgrimes#endif 7261541Srgrimes ep->e_vm.vm_tsize = vm->vm_tsize; 7271541Srgrimes ep->e_vm.vm_dsize = vm->vm_dsize; 7281541Srgrimes ep->e_vm.vm_ssize = vm->vm_ssize; 7291541Srgrimes#ifndef sparc 7301541Srgrimes ep->e_vm.vm_pmap = vm->vm_pmap; 7311541Srgrimes#endif 7321541Srgrimes } 7331541Srgrimes if (p->p_pptr) 7341541Srgrimes ep->e_ppid = p->p_pptr->p_pid; 7351541Srgrimes else 7361541Srgrimes ep->e_ppid = 0; 7371541Srgrimes ep->e_pgid = p->p_pgrp->pg_id; 7381541Srgrimes ep->e_jobc = p->p_pgrp->pg_jobc; 7391541Srgrimes if ((p->p_flag & P_CONTROLT) && 7401541Srgrimes (tp = ep->e_sess->s_ttyp)) { 7411541Srgrimes ep->e_tdev = tp->t_dev; 7421541Srgrimes ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 7431541Srgrimes ep->e_tsess = tp->t_session; 7441541Srgrimes } else 7451541Srgrimes ep->e_tdev = NODEV; 7461541Srgrimes ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 7471541Srgrimes if (SESS_LEADER(p)) 7481541Srgrimes ep->e_flag |= EPROC_SLEADER; 7491541Srgrimes if (p->p_wmesg) 7501541Srgrimes strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 7511541Srgrimes ep->e_xsize = ep->e_xrssize = 0; 7521541Srgrimes ep->e_xccount = ep->e_xswrss = 0; 7531541Srgrimes} 7541541Srgrimes 7551541Srgrimes#ifdef COMPAT_43 7561541Srgrimes#include <sys/socket.h> 7571541Srgrimes#define KINFO_PROC (0<<8) 7581541Srgrimes#define KINFO_RT (1<<8) 7591541Srgrimes#define KINFO_VNODE (2<<8) 7601541Srgrimes#define KINFO_FILE (3<<8) 7611541Srgrimes#define KINFO_METER (4<<8) 7621541Srgrimes#define KINFO_LOADAVG (5<<8) 7631541Srgrimes#define KINFO_CLOCKRATE (6<<8) 7641541Srgrimes 7651541Srgrimesstruct getkerninfo_args { 7661541Srgrimes int op; 7671541Srgrimes char *where; 7681541Srgrimes int *size; 7691541Srgrimes int arg; 7701541Srgrimes}; 7711541Srgrimes 7721549Srgrimesint 7731541Srgrimesogetkerninfo(p, uap, retval) 7741541Srgrimes struct proc *p; 7751541Srgrimes register struct getkerninfo_args *uap; 7761541Srgrimes int *retval; 7771541Srgrimes{ 7781541Srgrimes int error, name[5]; 7791541Srgrimes u_int size; 7801541Srgrimes 7811541Srgrimes if (uap->size && 7821541Srgrimes (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size)))) 7831541Srgrimes return (error); 7841541Srgrimes 7851541Srgrimes switch (uap->op & 0xff00) { 7861541Srgrimes 7871541Srgrimes case KINFO_RT: 7881541Srgrimes name[0] = PF_ROUTE; 7891541Srgrimes name[1] = 0; 7901541Srgrimes name[2] = (uap->op & 0xff0000) >> 16; 7911541Srgrimes name[3] = uap->op & 0xff; 7921541Srgrimes name[4] = uap->arg; 7931541Srgrimes error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p); 7941541Srgrimes break; 7951541Srgrimes 7961541Srgrimes case KINFO_VNODE: 7971541Srgrimes name[0] = KERN_VNODE; 7981541Srgrimes error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 7991541Srgrimes break; 8001541Srgrimes 8011541Srgrimes case KINFO_PROC: 8021541Srgrimes name[0] = KERN_PROC; 8031541Srgrimes name[1] = uap->op & 0xff; 8041541Srgrimes name[2] = uap->arg; 8051541Srgrimes error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p); 8061541Srgrimes break; 8071541Srgrimes 8081541Srgrimes case KINFO_FILE: 8091541Srgrimes name[0] = KERN_FILE; 8101541Srgrimes error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 8111541Srgrimes break; 8121541Srgrimes 8131541Srgrimes case KINFO_METER: 8141541Srgrimes name[0] = VM_METER; 8151541Srgrimes error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 8161541Srgrimes break; 8171541Srgrimes 8181541Srgrimes case KINFO_LOADAVG: 8191541Srgrimes name[0] = VM_LOADAVG; 8201541Srgrimes error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 8211541Srgrimes break; 8221541Srgrimes 8231541Srgrimes case KINFO_CLOCKRATE: 8241541Srgrimes name[0] = KERN_CLOCKRATE; 8251541Srgrimes error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 8261541Srgrimes break; 8271541Srgrimes 8281541Srgrimes default: 8291541Srgrimes return (EOPNOTSUPP); 8301541Srgrimes } 8311541Srgrimes if (error) 8321541Srgrimes return (error); 8331541Srgrimes *retval = size; 8341541Srgrimes if (uap->size) 8351541Srgrimes error = copyout((caddr_t)&size, (caddr_t)uap->size, 8361541Srgrimes sizeof(size)); 8371541Srgrimes return (error); 8381541Srgrimes} 8391541Srgrimes#endif /* COMPAT_43 */ 840