kern_sysctl.c revision 12243
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 3712243Sphk * $Id: kern_sysctl.c,v 1.37 1995/11/12 06:43:01 bde Exp $ 381541Srgrimes */ 391541Srgrimes 401541Srgrimes/* 411541Srgrimes * sysctl system call. 421541Srgrimes */ 431541Srgrimes 441541Srgrimes#include <sys/param.h> 451541Srgrimes#include <sys/systm.h> 4612221Sbde#include <sys/sysproto.h> 471541Srgrimes#include <sys/kernel.h> 481541Srgrimes#include <sys/malloc.h> 491541Srgrimes#include <sys/proc.h> 501541Srgrimes#include <sys/file.h> 511541Srgrimes#include <sys/vnode.h> 521541Srgrimes#include <sys/unistd.h> 531541Srgrimes#include <sys/buf.h> 541541Srgrimes#include <sys/ioctl.h> 551541Srgrimes#include <sys/tty.h> 568481Swollman#include <sys/conf.h> 571541Srgrimes#include <vm/vm.h> 581541Srgrimes#include <sys/sysctl.h> 5911865Sphk#include <sys/user.h> 601541Srgrimes 6112152Sphkextern struct linker_set sysctl_; 6212152Sphk 6311863Sphk/* BEGIN_MIB */ 6412243SphkSYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, 6512152Sphk "Sysctl internal magic"); 6612243SphkSYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, 6712131Sphk "High kernel, proc, limits &c"); 6812243SphkSYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, 6912131Sphk "Virtual memory"); 7012243SphkSYSCTL_NODE(, CTL_FS, fs, CTLFLAG_RW, 0, 7112131Sphk "File system"); 7212243SphkSYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, 7312131Sphk "Network, (see socket.h)"); 7412243SphkSYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, 7512131Sphk "Debugging"); 7612243SphkSYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, 7712131Sphk "hardware"); 7812243SphkSYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, 7912131Sphk "machine dependent"); 8012243SphkSYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, 8112131Sphk "user-level"); 8211863Sphk 8312131SphkSYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, ""); 8411863Sphk 8512131SphkSYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, ""); 8611863Sphk 8712131SphkSYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, ""); 8811863Sphk 8912131SphkSYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, ""); 9011863Sphk 9111863Sphkextern int osreldate; 9212131SphkSYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, ""); 9311863Sphk 9412131SphkSYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, ""); 9511863Sphk 9612131SphkSYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, ""); 9711863Sphk 9812131SphkSYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, 9911865Sphk CTLFLAG_RD, &maxprocperuid, 0, ""); 10011863Sphk 10112131SphkSYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, 10211865Sphk CTLFLAG_RD, &maxfilesperproc, 0, ""); 10311863Sphk 10412131SphkSYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, ""); 10511863Sphk 10612131SphkSYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, ""); 10711863Sphk 10812131SphkSYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, ""); 10911863Sphk 11012131SphkSYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, ""); 11111863Sphk 11212131SphkSYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, ""); 11311863Sphk 11411863Sphk#ifdef _POSIX_SAVED_IDS 11512131SphkSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, ""); 11612243Sphk#else 11712131SphkSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, ""); 11811863Sphk#endif 11911863Sphk 12011863Sphkchar kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ 12111863Sphk 12212131SphkSYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, 12311865Sphk CTLFLAG_RW, kernelname, sizeof kernelname, ""); 12411863Sphk 12512131SphkSYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, 12611865Sphk CTLFLAG_RW, &boottime, timeval, ""); 12711863Sphk 12812131SphkSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); 12911863Sphk 13012152SphkSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); 13111863Sphk 13212131SphkSYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, ""); 13311863Sphk 13412131SphkSYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, ""); 13511863Sphk 13612131SphkSYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, ""); 13711863Sphk 13811863Sphk/* END_MIB */ 13911863Sphk 14011863Sphkextern int vfs_update_wakeup; 14111863Sphkextern int vfs_update_interval; 14211863Sphkstatic int 14311865Sphksysctl_kern_updateinterval SYSCTL_HANDLER_ARGS 14411863Sphk{ 14511865Sphk int error = sysctl_handle_int(oidp, 14612243Sphk oidp->oid_arg1, oidp->oid_arg2, req); 14711865Sphk if (!error) 14811863Sphk wakeup(&vfs_update_wakeup); 14911865Sphk return error; 15011863Sphk} 15111863Sphk 15212131SphkSYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW, 15312131Sphk &vfs_update_interval, 0, sysctl_kern_updateinterval, ""); 15411863Sphk 15512131Sphk 15612131Sphkchar hostname[MAXHOSTNAMELEN]; 15712131Sphkint hostnamelen; 15812131Sphkstatic int 15912131Sphksysctl_kern_hostname SYSCTL_HANDLER_ARGS 16012131Sphk{ 16112131Sphk int error = sysctl_handle_string(oidp, 16212243Sphk oidp->oid_arg1, oidp->oid_arg2, req); 16312243Sphk if (req->newptr && (error == 0 || error == ENOMEM)) 16412243Sphk hostnamelen = req->newlen; 16512131Sphk return error; 16612131Sphk} 16712131Sphk 16812131SphkSYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW, 16912131Sphk &hostname, sizeof(hostname), sysctl_kern_hostname, ""); 17012131Sphk 17112152Sphkstatic int 17212197Sbdesysctl_order_cmp(const void *a, const void *b) 17312152Sphk{ 17412197Sbde const struct sysctl_oid **pa, **pb; 17512197Sbde 17612197Sbde pa = (const struct sysctl_oid **)a; 17712197Sbde pb = (const struct sysctl_oid **)b; 17812197Sbde if (*pa == NULL) 17912197Sbde return (1); 18012197Sbde if (*pb == NULL) 18112197Sbde return (-1); 18212152Sphk return ((*pa)->oid_number - (*pb)->oid_number); 18312152Sphk} 18412131Sphk 18512152Sphkstatic void 18612152Sphksysctl_order(void *arg) 18712152Sphk{ 18812171Sphk int j; 18912152Sphk struct linker_set *l = (struct linker_set *) arg; 19012152Sphk struct sysctl_oid **oidpp; 19112152Sphk 19212152Sphk j = l->ls_length; 19312152Sphk oidpp = (struct sysctl_oid **) l->ls_items; 19412152Sphk for (; j--; oidpp++) { 19512152Sphk if (!*oidpp) 19612152Sphk continue; 19712152Sphk if ((*oidpp)->oid_arg1 == arg) { 19812152Sphk *oidpp = 0; 19912152Sphk continue; 20012152Sphk } 20112243Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 20212152Sphk if (!(*oidpp)->oid_handler) 20312152Sphk sysctl_order((*oidpp)->oid_arg1); 20412152Sphk } 20512152Sphk qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 20612152Sphk sysctl_order_cmp); 20712152Sphk} 20812152Sphk 20912243SphkSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_); 21012152Sphk 21112152Sphkstatic void 21212243Sphksysctl_sysctl_debug_dump_node(struct linker_set *l, int i) 21312152Sphk{ 21412243Sphk int j, k; 21512152Sphk struct sysctl_oid **oidpp; 21612152Sphk 21712152Sphk j = l->ls_length; 21812152Sphk oidpp = (struct sysctl_oid **) l->ls_items; 21912152Sphk for (; j--; oidpp++) { 22012152Sphk 22112152Sphk if (!*oidpp) 22212152Sphk continue; 22312152Sphk 22412152Sphk for (k=0; k<i; k++) 22512152Sphk printf(" "); 22612152Sphk 22712152Sphk if ((*oidpp)->oid_number > 100) { 22812171Sphk printf("Junk! %p # %d %s k %x a1 %p a2 %x h %p\n", 22912152Sphk *oidpp, 23012152Sphk (*oidpp)->oid_number, (*oidpp)->oid_name, 23112152Sphk (*oidpp)->oid_kind, (*oidpp)->oid_arg1, 23212152Sphk (*oidpp)->oid_arg2, (*oidpp)->oid_handler); 23312152Sphk continue; 23412152Sphk } 23512152Sphk printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 23612152Sphk 23712152Sphk printf("%c%c", 23812152Sphk (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 23912152Sphk (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 24012152Sphk 24112152Sphk switch ((*oidpp)->oid_kind & CTLTYPE) { 24212243Sphk case CTLTYPE_NODE: 24312152Sphk if ((*oidpp)->oid_handler) { 24412243Sphk printf(" Node(proc)\n"); 24512152Sphk } else { 24612243Sphk printf(" Node\n"); 24712152Sphk sysctl_sysctl_debug_dump_node( 24812243Sphk (*oidpp)->oid_arg1, i+2); 24912152Sphk } 25012152Sphk break; 25112152Sphk case CTLTYPE_INT: printf(" Int\n"); break; 25212152Sphk case CTLTYPE_STRING: printf(" String\n"); break; 25312152Sphk case CTLTYPE_QUAD: printf(" Quad\n"); break; 25412152Sphk case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 25512152Sphk default: printf("\n"); 25612152Sphk } 25712152Sphk 25812152Sphk } 25912152Sphk} 26012152Sphk 26112152Sphk 26212152Sphkstatic int 26312152Sphksysctl_sysctl_debug SYSCTL_HANDLER_ARGS 26412152Sphk{ 26512243Sphk sysctl_sysctl_debug_dump_node(&sysctl_, 0); 26612152Sphk return ENOENT; 26712152Sphk} 26812152Sphk 26912152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 27012152Sphk 0, 0, sysctl_sysctl_debug, ""); 27112152Sphk 27212131Sphkchar domainname[MAXHOSTNAMELEN]; 27312131Sphkint domainnamelen; 27412131Sphkstatic int 27512131Sphksysctl_kern_domainname SYSCTL_HANDLER_ARGS 27612131Sphk{ 27712131Sphk int error = sysctl_handle_string(oidp, 27812243Sphk oidp->oid_arg1, oidp->oid_arg2, req); 27912243Sphk if (req->newptr && (error == 0 || error == ENOMEM)) 28012243Sphk domainnamelen = req->newlen; 28112131Sphk return error; 28212131Sphk} 28312131Sphk 28412131SphkSYSCTL_PROC(_kern, KERN_DOMAINNAME, domainname, CTLTYPE_STRING|CTLFLAG_RW, 28512131Sphk &domainname, sizeof(domainname), sysctl_kern_domainname, ""); 28612131Sphk 28712131Sphklong hostid; 28812131Sphk/* Some trouble here, if sizeof (int) != sizeof (long) */ 28912131SphkSYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, ""); 29012131Sphk 29112243Sphk/* 29212243Sphk * Handle an integer, signed or unsigned. 29312243Sphk * Two cases: 29412243Sphk * a variable: point arg1 at it. 29512243Sphk * a constant: pass it in arg2. 29612243Sphk */ 29712243Sphk 29811865Sphkint 29911865Sphksysctl_handle_int SYSCTL_HANDLER_ARGS 30011863Sphk{ 30112243Sphk int error = 0; 30211863Sphk 30312243Sphk if (arg1) 30412243Sphk error = SYSCTL_OUT(req, arg1, sizeof(int)); 30512243Sphk else if (arg2) 30612243Sphk error = SYSCTL_OUT(req, &arg2, sizeof(int)); 30711863Sphk 30812243Sphk if (error || !req->newptr) 30912243Sphk return (error); 31011863Sphk 31112243Sphk if (!arg1) 31212243Sphk error = EPERM; 31312243Sphk else 31412243Sphk error = SYSCTL_IN(req, arg1, sizeof(int)); 31512243Sphk return (error); 31611863Sphk} 31711863Sphk 31812243Sphk/* 31912243Sphk * Handle our generic '\0' terminated 'C' string. 32012243Sphk * Two cases: 32112243Sphk * a variable string: point arg1 at it, arg2 is max length. 32212243Sphk * a constant string: point arg1 at it, arg2 is zero. 32312243Sphk */ 32412243Sphk 32511865Sphkint 32611865Sphksysctl_handle_string SYSCTL_HANDLER_ARGS 32711863Sphk{ 32812243Sphk int error=0; 32911863Sphk 33012243Sphk if (arg2) 33112243Sphk error = SYSCTL_OUT(req, arg1, arg2); 33212243Sphk else 33312243Sphk error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1); 33411863Sphk 33512243Sphk if (error || !req->newptr) 33612243Sphk return (error); 33711863Sphk 33812243Sphk if ((req->newlen - req->newidx) > arg2) { 33912243Sphk error = E2BIG; 34012243Sphk } else { 34112243Sphk arg2 = (req->newlen - req->newidx); 34212243Sphk error = SYSCTL_IN(req, arg1, arg2); 34312243Sphk ((char *)arg1)[arg2] = '\0'; 34411863Sphk } 34512131Sphk 34612131Sphk return (error); 34711863Sphk} 34811863Sphk 34912243Sphk/* 35012243Sphk * Handle any kind of opaque data. 35112243Sphk * arg1 points to it, arg2 is the size. 35212243Sphk */ 35312243Sphk 35411865Sphkint 35511865Sphksysctl_handle_opaque SYSCTL_HANDLER_ARGS 35611863Sphk{ 35712243Sphk int error; 35812243Sphk 35912243Sphk error = SYSCTL_OUT(req, arg1, arg2); 36012243Sphk 36112243Sphk if (error || !req->newptr) 36212243Sphk return (error); 36312243Sphk 36412243Sphk error = SYSCTL_IN(req, arg1, arg2); 36512243Sphk 36612243Sphk return (error); 36712243Sphk} 36812243Sphk 36912243Sphkint 37012243Sphksysctl_old_kernel(struct sysctl_req *req, void *p, int l) 37112243Sphk{ 37212243Sphk int i = min(req->oldlen - req->oldidx, l); 37312243Sphk if (i) { 37412243Sphk bcopy(p, req->oldptr + req->oldidx, i); 37512243Sphk req->oldidx += i; 37612243Sphk } 37712243Sphk if (i != l) 37811863Sphk return (ENOMEM); 37912243Sphk else 38012243Sphk return (0); 38111863Sphk 38212243Sphk} 38312243Sphk 38412243Sphkint 38512243Sphksysctl_new_kernel(struct sysctl_req *req, void *p, int l) 38612243Sphk{ 38712243Sphk int i = req->newlen - req->newidx; 38812243Sphk if (i < l) 38911863Sphk return (EINVAL); 39012243Sphk bcopy(req->newptr + req->newidx, p, l); 39112243Sphk req->newidx += l; 39212131Sphk return (0); 39311863Sphk} 39411863Sphk 39512243Sphkint 39612243Sphksysctl_old_user(struct sysctl_req *req, void *p, int l) 39712243Sphk{ 39812243Sphk int error , i = min(req->oldlen - req->oldidx, l); 39912243Sphk 40012243Sphk error = copyout(p, req->oldptr + req->oldidx, i); 40112243Sphk req->oldidx += i; 40212243Sphk if (error) 40312243Sphk return (error); 40412243Sphk if (i < l) 40512243Sphk return (ENOMEM); 40612243Sphk return (error); 40712243Sphk} 40812243Sphk 40912243Sphkint 41012243Sphksysctl_new_user(struct sysctl_req *req, void *p, int l) 41112243Sphk{ 41212243Sphk int error, i = req->newlen - req->newidx; 41312243Sphk if (i < l) 41412243Sphk return (EINVAL); 41512243Sphk error = copyin(req->newptr + req->newidx, p, l); 41612243Sphk req->newidx += l; 41712243Sphk return (error); 41812243Sphk} 41912243Sphk 42011865Sphk#ifdef DEBUG 42111865Sphkstatic sysctlfn debug_sysctl; 42211865Sphk#endif 42311863Sphk 4241541Srgrimes/* 4251541Srgrimes * Locking and stats 4261541Srgrimes */ 4271541Srgrimesstatic struct sysctl_lock { 4281541Srgrimes int sl_lock; 4291541Srgrimes int sl_want; 4301541Srgrimes int sl_locked; 4311541Srgrimes} memlock; 4321541Srgrimes 4331541Srgrimes 43412131Sphk 43512131Sphk/* 43612131Sphk * Traverse our tree, and find the right node, execute whatever it points 43712131Sphk * at, and return the resulting error code. 43812131Sphk * We work entirely in kernel-space at this time. 43912131Sphk */ 44012131Sphk 44111863Sphk 4421541Srgrimesint 44312131Sphksysctl_root SYSCTL_HANDLER_ARGS 44412131Sphk{ 44512131Sphk int *name = (int *) arg1; 44612131Sphk int namelen = arg2; 44712131Sphk int indx, i, j; 44812131Sphk struct sysctl_oid **oidpp; 44912131Sphk struct linker_set *lsp = &sysctl_; 45012131Sphk 45112131Sphk j = lsp->ls_length; 45212131Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 45312131Sphk 45412131Sphk indx = 0; 45512131Sphk while (j-- && indx < CTL_MAXNAME) { 45612152Sphk if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 45712131Sphk indx++; 45812131Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 45912131Sphk if ((*oidpp)->oid_handler) 46012131Sphk goto found; 46112243Sphk if (indx == namelen) 46212131Sphk return ENOENT; 46312131Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 46412131Sphk j = lsp->ls_length; 46512131Sphk oidpp = (struct sysctl_oid **)lsp->ls_items; 46612131Sphk } else { 46712243Sphk if (indx != namelen) 46812131Sphk return EISDIR; 46912131Sphk goto found; 47012131Sphk } 47112131Sphk } else { 47212131Sphk oidpp++; 47312131Sphk } 47412131Sphk } 47512131Sphk return EJUSTRETURN; 47612131Sphkfound: 47712131Sphk 47812131Sphk /* If writing isn't allowed */ 47912243Sphk if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR)) 48012131Sphk return (EPERM); 48112131Sphk 48212243Sphk if (!(*oidpp)->oid_handler) 48312131Sphk return EINVAL; 48412131Sphk 48512131Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 48612131Sphk i = ((*oidpp)->oid_handler) (*oidpp, 48712131Sphk name + indx, namelen - indx, 48812243Sphk req); 48912131Sphk } else { 49012131Sphk i = ((*oidpp)->oid_handler) (*oidpp, 49112131Sphk (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 49212243Sphk req); 49312131Sphk } 49412131Sphk return (i); 49512131Sphk} 49612131Sphk 49712221Sbde#ifndef _SYS_SYSPROTO_H_ 49812171Sphkstruct sysctl_args { 49912171Sphk int *name; 50012171Sphk u_int namelen; 50112171Sphk void *old; 50212171Sphk size_t *oldlenp; 50312171Sphk void *new; 50412171Sphk size_t newlen; 50512171Sphk}; 50612221Sbde#endif 50712171Sphk 50812131Sphkint 5091541Srgrimes__sysctl(p, uap, retval) 5101541Srgrimes struct proc *p; 5111541Srgrimes register struct sysctl_args *uap; 5121541Srgrimes int *retval; 5131541Srgrimes{ 51412171Sphk int error, name[CTL_MAXNAME]; 5151541Srgrimes 5161541Srgrimes if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 5171541Srgrimes return (EINVAL); 51811863Sphk 5193308Sphk error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 5203308Sphk if (error) 5211541Srgrimes return (error); 5221541Srgrimes 52312171Sphk return (userland_sysctl(p, name, uap->namelen, 52412171Sphk uap->old, uap->oldlenp, 0, 52512171Sphk uap->new, uap->newlen, retval)); 52612171Sphk} 52712171Sphk 52812187Sphkstatic sysctlfn kern_sysctl; 52912187Sphk 53012171Sphk/* 53112171Sphk * This is used from various compatibility syscalls too. That's why name 53212171Sphk * must be in kernel space. 53312171Sphk */ 53412171Sphkint 53512171Sphkuserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval) 53612171Sphk{ 53712243Sphk int error = 0, dolock = 1, i, oldlen = 0; 53812243Sphk u_int savelen = 0; 53912171Sphk sysctlfn *fn; 54012243Sphk struct sysctl_req req; 54112171Sphk 54212243Sphk bzero(&req, sizeof req); 54312243Sphk 54412171Sphk if (new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 54512131Sphk return (error); 54611863Sphk 54712171Sphk if (oldlenp) { 54812171Sphk if (inkernel) { 54912243Sphk req.oldlen = *oldlenp; 55012171Sphk } else { 55112243Sphk error = copyin(oldlenp, &req.oldlen, 55212243Sphk sizeof(req.oldlen)); 55312171Sphk if (error) 55412171Sphk return (error); 55512171Sphk } 55612243Sphk oldlen = req.oldlen; 55712171Sphk } 55812171Sphk 55912243Sphk if (old) { 56012243Sphk if (!useracc(old, req.oldlen, B_WRITE)) 56112243Sphk return (EFAULT); 56212243Sphk req.oldptr= old; 56312243Sphk } 56412131Sphk 56512171Sphk if (newlen) { 56612243Sphk if (!useracc(new, req.newlen, B_READ)) 56712243Sphk return (EFAULT); 56812243Sphk req.newlen = newlen; 56912243Sphk req.newptr = new; 57011863Sphk } 57112131Sphk 57212243Sphk req.oldfunc = sysctl_old_user; 57312243Sphk req.newfunc = sysctl_new_user; 57411863Sphk 57512243Sphk error = sysctl_root(0, name, namelen, &req); 57612243Sphk 57712131Sphk if (!error || error == ENOMEM) { 57812194Sphk if (retval) 57912243Sphk *retval = req.oldlen; 58012171Sphk if (oldlenp) { 58112171Sphk if (inkernel) { 58212243Sphk *oldlenp = req.oldlen; 58312171Sphk } else { 58412243Sphk i = copyout(&req.oldlen, oldlenp, 58512243Sphk sizeof(req.oldlen)); 58612171Sphk if (i) 58712171Sphk error = i; 58812171Sphk } 58912131Sphk } 59011863Sphk return (error); 59111863Sphk } 59211863Sphk 5931541Srgrimes switch (name[0]) { 5941541Srgrimes case CTL_KERN: 5951541Srgrimes fn = kern_sysctl; 5962903Sache if (name[1] != KERN_VNODE) /* XXX */ 5971541Srgrimes dolock = 0; 5981541Srgrimes break; 5991541Srgrimes case CTL_HW: 6001541Srgrimes fn = hw_sysctl; 6011541Srgrimes break; 6021541Srgrimes case CTL_VM: 6031541Srgrimes fn = vm_sysctl; 6041541Srgrimes break; 6051541Srgrimes case CTL_NET: 6061541Srgrimes fn = net_sysctl; 6071541Srgrimes break; 6081541Srgrimes case CTL_FS: 6091541Srgrimes fn = fs_sysctl; 6101541Srgrimes break; 6111541Srgrimes#ifdef DEBUG 6121541Srgrimes case CTL_DEBUG: 6131541Srgrimes fn = debug_sysctl; 6141541Srgrimes break; 6151541Srgrimes#endif 6161541Srgrimes default: 6171541Srgrimes return (EOPNOTSUPP); 6181541Srgrimes } 61912171Sphk if (old != NULL) { 62012171Sphk if (!useracc(old, oldlen, B_WRITE)) 6211541Srgrimes return (EFAULT); 6221541Srgrimes while (memlock.sl_lock) { 6231541Srgrimes memlock.sl_want = 1; 6243396Sdg (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 6251541Srgrimes memlock.sl_locked++; 6261541Srgrimes } 6271541Srgrimes memlock.sl_lock = 1; 6281541Srgrimes if (dolock) 62912171Sphk vslock(old, oldlen); 6301541Srgrimes savelen = oldlen; 6311541Srgrimes } 63211863Sphk 63311863Sphk 63412171Sphk error = (*fn)(name + 1, namelen - 1, old, &oldlen, 63512171Sphk new, newlen, p); 63612131Sphk 63712131Sphk 63812171Sphk if (old != NULL) { 6391541Srgrimes if (dolock) 64012171Sphk vsunlock(old, savelen, B_WRITE); 6411541Srgrimes memlock.sl_lock = 0; 6421541Srgrimes if (memlock.sl_want) { 6431541Srgrimes memlock.sl_want = 0; 6441541Srgrimes wakeup((caddr_t)&memlock); 6451541Srgrimes } 6461541Srgrimes } 64712152Sphk#if 0 64812152Sphk if (error) { 64912152Sphk printf("SYSCTL_ERROR: "); 65012171Sphk for(i=0;i<namelen;i++) 65112152Sphk printf("%d ", name[i]); 65212152Sphk printf("= %d\n", error); 65312152Sphk } 65412152Sphk#endif 6551541Srgrimes if (error) 6561541Srgrimes return (error); 65712171Sphk if (retval) 65812171Sphk *retval = oldlen; 65912171Sphk if (oldlenp) { 66012171Sphk if (inkernel) { 66112171Sphk *oldlenp = oldlen; 66212171Sphk } else { 66312171Sphk error = copyout(&oldlen, oldlenp, sizeof(oldlen)); 66412171Sphk } 66512171Sphk } 66612171Sphk return (error); 6671541Srgrimes} 6681541Srgrimes 6691541Srgrimes/* 6701541Srgrimes * Attributes stored in the kernel. 6711541Srgrimes */ 6721995Swollmanint securelevel = -1; 6731541Srgrimes 6741541Srgrimes/* 6751541Srgrimes * kernel related system variables. 6761541Srgrimes */ 67712197Sbdestatic int 6781541Srgrimeskern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 6791541Srgrimes int *name; 6801541Srgrimes u_int namelen; 6811541Srgrimes void *oldp; 6821541Srgrimes size_t *oldlenp; 6831541Srgrimes void *newp; 6841541Srgrimes size_t newlen; 6851541Srgrimes struct proc *p; 6861541Srgrimes{ 68712131Sphk int error, level; 6888481Swollman dev_t ndumpdev; 6891541Srgrimes 6901541Srgrimes /* all sysctl names at this level are terminal */ 6912858Swollman if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF 6922858Swollman || name[0] == KERN_NTP_PLL)) 6931541Srgrimes return (ENOTDIR); /* overloaded */ 6941541Srgrimes 6951541Srgrimes switch (name[0]) { 69611863Sphk 6971541Srgrimes case KERN_SECURELVL: 6981541Srgrimes level = securelevel; 6991541Srgrimes if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 7001541Srgrimes newp == NULL) 7011541Srgrimes return (error); 7021541Srgrimes if (level < securelevel && p->p_pid != 1) 7031541Srgrimes return (EPERM); 7041541Srgrimes securelevel = level; 7051541Srgrimes return (0); 7061541Srgrimes case KERN_VNODE: 7071541Srgrimes return (sysctl_vnode(oldp, oldlenp)); 7081541Srgrimes case KERN_PROC: 7091541Srgrimes return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 7101541Srgrimes case KERN_FILE: 7111541Srgrimes return (sysctl_file(oldp, oldlenp)); 7121541Srgrimes#ifdef GPROF 7131541Srgrimes case KERN_PROF: 7141541Srgrimes return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 7151541Srgrimes newp, newlen)); 7161541Srgrimes#endif 7172858Swollman case KERN_NTP_PLL: 7182858Swollman return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp, 7192858Swollman newp, newlen, p)); 7208481Swollman case KERN_DUMPDEV: 7218481Swollman ndumpdev = dumpdev; 7228481Swollman error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev, 7238481Swollman sizeof ndumpdev); 7248481Swollman if (!error && ndumpdev != dumpdev) { 7258481Swollman error = setdumpdev(ndumpdev); 7268481Swollman } 7278481Swollman return error; 7281541Srgrimes default: 7291541Srgrimes return (EOPNOTSUPP); 7301541Srgrimes } 7311541Srgrimes /* NOTREACHED */ 7321541Srgrimes} 7331541Srgrimes 7341541Srgrimes/* 7351541Srgrimes * hardware related system variables. 7361541Srgrimes */ 7371549Srgrimesint 7381541Srgrimeshw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 7391541Srgrimes int *name; 7401541Srgrimes u_int namelen; 7411541Srgrimes void *oldp; 7421541Srgrimes size_t *oldlenp; 7431541Srgrimes void *newp; 7441541Srgrimes size_t newlen; 7451541Srgrimes struct proc *p; 7461541Srgrimes{ 7473640Swollman /* almost all sysctl names at this level are terminal */ 7483640Swollman if (namelen != 1 && name[0] != HW_DEVCONF) 7491541Srgrimes return (ENOTDIR); /* overloaded */ 7501541Srgrimes 7511541Srgrimes switch (name[0]) { 7521541Srgrimes case HW_PHYSMEM: 7531541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 7541541Srgrimes case HW_USERMEM: 7551541Srgrimes return (sysctl_rdint(oldp, oldlenp, newp, 7561541Srgrimes ctob(physmem - cnt.v_wire_count))); 7573640Swollman case HW_DEVCONF: 7583640Swollman return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp, 7593640Swollman newp, newlen, p)); 7601541Srgrimes default: 7611541Srgrimes return (EOPNOTSUPP); 7621541Srgrimes } 7631541Srgrimes /* NOTREACHED */ 7641541Srgrimes} 7651541Srgrimes 7661541Srgrimes#ifdef DEBUG 7671541Srgrimes/* 7681541Srgrimes * Debugging related system variables. 7691541Srgrimes */ 7701541Srgrimesstruct ctldebug debug0, debug1, debug2, debug3, debug4; 7711541Srgrimesstruct ctldebug debug5, debug6, debug7, debug8, debug9; 7721541Srgrimesstruct ctldebug debug10, debug11, debug12, debug13, debug14; 7731541Srgrimesstruct ctldebug debug15, debug16, debug17, debug18, debug19; 7741541Srgrimesstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 7751541Srgrimes &debug0, &debug1, &debug2, &debug3, &debug4, 7761541Srgrimes &debug5, &debug6, &debug7, &debug8, &debug9, 7771541Srgrimes &debug10, &debug11, &debug12, &debug13, &debug14, 7781541Srgrimes &debug15, &debug16, &debug17, &debug18, &debug19, 7791541Srgrimes}; 7804467Sbdestatic int 7811541Srgrimesdebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 7821541Srgrimes int *name; 7831541Srgrimes u_int namelen; 7841541Srgrimes void *oldp; 7851541Srgrimes size_t *oldlenp; 7861541Srgrimes void *newp; 7871541Srgrimes size_t newlen; 7881541Srgrimes struct proc *p; 7891541Srgrimes{ 7901541Srgrimes struct ctldebug *cdp; 7911541Srgrimes 7921541Srgrimes /* all sysctl names at this level are name and field */ 7931541Srgrimes if (namelen != 2) 7941541Srgrimes return (ENOTDIR); /* overloaded */ 7951541Srgrimes cdp = debugvars[name[0]]; 7961541Srgrimes if (cdp->debugname == 0) 7971541Srgrimes return (EOPNOTSUPP); 7981541Srgrimes switch (name[1]) { 7991541Srgrimes case CTL_DEBUG_NAME: 8001541Srgrimes return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 8011541Srgrimes case CTL_DEBUG_VALUE: 8021541Srgrimes return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 8031541Srgrimes default: 8041541Srgrimes return (EOPNOTSUPP); 8051541Srgrimes } 8061541Srgrimes /* NOTREACHED */ 8071541Srgrimes} 8081541Srgrimes#endif /* DEBUG */ 8091541Srgrimes 8101541Srgrimes/* 8111541Srgrimes * Validate parameters and get old / set new parameters 8121541Srgrimes * for an integer-valued sysctl function. 8131541Srgrimes */ 8141549Srgrimesint 8151541Srgrimessysctl_int(oldp, oldlenp, newp, newlen, valp) 8161541Srgrimes void *oldp; 8171541Srgrimes size_t *oldlenp; 8181541Srgrimes void *newp; 8191541Srgrimes size_t newlen; 8201541Srgrimes int *valp; 8211541Srgrimes{ 8221541Srgrimes int error = 0; 8231541Srgrimes 8241541Srgrimes if (oldp && *oldlenp < sizeof(int)) 8251541Srgrimes return (ENOMEM); 8261541Srgrimes if (newp && newlen != sizeof(int)) 8271541Srgrimes return (EINVAL); 8281541Srgrimes *oldlenp = sizeof(int); 8291541Srgrimes if (oldp) 8301541Srgrimes error = copyout(valp, oldp, sizeof(int)); 8311541Srgrimes if (error == 0 && newp) 8321541Srgrimes error = copyin(newp, valp, sizeof(int)); 8331541Srgrimes return (error); 8341541Srgrimes} 8351541Srgrimes 8361541Srgrimes/* 8371541Srgrimes * As above, but read-only. 8381541Srgrimes */ 8391549Srgrimesint 8401541Srgrimessysctl_rdint(oldp, oldlenp, newp, val) 8411541Srgrimes void *oldp; 8421541Srgrimes size_t *oldlenp; 8431541Srgrimes void *newp; 8441541Srgrimes int val; 8451541Srgrimes{ 8461541Srgrimes int error = 0; 8471541Srgrimes 8481541Srgrimes if (oldp && *oldlenp < sizeof(int)) 8491541Srgrimes return (ENOMEM); 8501541Srgrimes if (newp) 8511541Srgrimes return (EPERM); 8521541Srgrimes *oldlenp = sizeof(int); 8531541Srgrimes if (oldp) 8541541Srgrimes error = copyout((caddr_t)&val, oldp, sizeof(int)); 8551541Srgrimes return (error); 8561541Srgrimes} 8571541Srgrimes 8581541Srgrimes/* 8591541Srgrimes * Validate parameters and get old / set new parameters 8601541Srgrimes * for a string-valued sysctl function. 8611541Srgrimes */ 8621549Srgrimesint 8631541Srgrimessysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 8641541Srgrimes void *oldp; 8651541Srgrimes size_t *oldlenp; 8661541Srgrimes void *newp; 8671541Srgrimes size_t newlen; 8681541Srgrimes char *str; 8691541Srgrimes int maxlen; 8701541Srgrimes{ 8719816Smpp int len, error = 0, rval = 0; 8721541Srgrimes 8731541Srgrimes len = strlen(str) + 1; 8749816Smpp if (oldp && *oldlenp < len) { 8755150Sguido len = *oldlenp; 8769816Smpp rval = ENOMEM; 8779816Smpp } 8781541Srgrimes if (newp && newlen >= maxlen) 8791541Srgrimes return (EINVAL); 8801541Srgrimes if (oldp) { 8811541Srgrimes *oldlenp = len; 8821541Srgrimes error = copyout(str, oldp, len); 8839816Smpp if (error) 8849816Smpp rval = error; 8851541Srgrimes } 8869816Smpp if ((error == 0 || error == ENOMEM) && newp) { 8871541Srgrimes error = copyin(newp, str, newlen); 8889816Smpp if (error) 8899816Smpp rval = error; 8901541Srgrimes str[newlen] = 0; 8911541Srgrimes } 8929816Smpp return (rval); 8931541Srgrimes} 8941541Srgrimes 8951541Srgrimes/* 8961541Srgrimes * As above, but read-only. 8971541Srgrimes */ 8981549Srgrimesint 8991541Srgrimessysctl_rdstring(oldp, oldlenp, newp, str) 9001541Srgrimes void *oldp; 9011541Srgrimes size_t *oldlenp; 9021541Srgrimes void *newp; 9031541Srgrimes char *str; 9041541Srgrimes{ 9059816Smpp int len, error = 0, rval = 0; 9061541Srgrimes 9071541Srgrimes len = strlen(str) + 1; 9089816Smpp if (oldp && *oldlenp < len) { 9099816Smpp len = *oldlenp; 9109816Smpp rval = ENOMEM; 9119816Smpp } 9121541Srgrimes if (newp) 9131541Srgrimes return (EPERM); 9141541Srgrimes *oldlenp = len; 9151541Srgrimes if (oldp) 9161541Srgrimes error = copyout(str, oldp, len); 9179816Smpp if (error) 9189816Smpp rval = error; 9199816Smpp return (rval); 9201541Srgrimes} 9211541Srgrimes 9221541Srgrimes/* 9231541Srgrimes * Validate parameters and get old / set new parameters 9241541Srgrimes * for a structure oriented sysctl function. 9251541Srgrimes */ 9261549Srgrimesint 9271541Srgrimessysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 9281541Srgrimes void *oldp; 9291541Srgrimes size_t *oldlenp; 9301541Srgrimes void *newp; 9311541Srgrimes size_t newlen; 9321541Srgrimes void *sp; 9331541Srgrimes int len; 9341541Srgrimes{ 9351541Srgrimes int error = 0; 9361541Srgrimes 9371541Srgrimes if (oldp && *oldlenp < len) 9381541Srgrimes return (ENOMEM); 9391541Srgrimes if (newp && newlen > len) 9401541Srgrimes return (EINVAL); 9411541Srgrimes if (oldp) { 9421541Srgrimes *oldlenp = len; 9431541Srgrimes error = copyout(sp, oldp, len); 9441541Srgrimes } 9451541Srgrimes if (error == 0 && newp) 9461541Srgrimes error = copyin(newp, sp, len); 9471541Srgrimes return (error); 9481541Srgrimes} 9491541Srgrimes 9501541Srgrimes/* 9511541Srgrimes * Validate parameters and get old parameters 9521541Srgrimes * for a structure oriented sysctl function. 9531541Srgrimes */ 9541549Srgrimesint 9551541Srgrimessysctl_rdstruct(oldp, oldlenp, newp, sp, len) 9561541Srgrimes void *oldp; 9571541Srgrimes size_t *oldlenp; 9581541Srgrimes void *newp, *sp; 9591541Srgrimes int len; 9601541Srgrimes{ 9611541Srgrimes int error = 0; 9621541Srgrimes 9631541Srgrimes if (oldp && *oldlenp < len) 9641541Srgrimes return (ENOMEM); 9651541Srgrimes if (newp) 9661541Srgrimes return (EPERM); 9671541Srgrimes *oldlenp = len; 9681541Srgrimes if (oldp) 9691541Srgrimes error = copyout(sp, oldp, len); 9701541Srgrimes return (error); 9711541Srgrimes} 9721541Srgrimes 9731541Srgrimes/* 9741541Srgrimes * Get file structures. 9751541Srgrimes */ 9761549Srgrimesint 9771541Srgrimessysctl_file(where, sizep) 9781541Srgrimes char *where; 9791541Srgrimes size_t *sizep; 9801541Srgrimes{ 9811541Srgrimes int buflen, error; 9821541Srgrimes struct file *fp; 9831541Srgrimes char *start = where; 9841541Srgrimes 9851541Srgrimes buflen = *sizep; 9861541Srgrimes if (where == NULL) { 9871541Srgrimes /* 9881541Srgrimes * overestimate by 10 files 9891541Srgrimes */ 9901541Srgrimes *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 9911541Srgrimes return (0); 9921541Srgrimes } 9931541Srgrimes 9941541Srgrimes /* 9951541Srgrimes * first copyout filehead 9961541Srgrimes */ 9971541Srgrimes if (buflen < sizeof(filehead)) { 9981541Srgrimes *sizep = 0; 9991541Srgrimes return (0); 10001541Srgrimes } 10013308Sphk error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 10023308Sphk if (error) 10031541Srgrimes return (error); 10041541Srgrimes buflen -= sizeof(filehead); 10051541Srgrimes where += sizeof(filehead); 10061541Srgrimes 10071541Srgrimes /* 10081541Srgrimes * followed by an array of file structures 10091541Srgrimes */ 10101541Srgrimes for (fp = filehead; fp != NULL; fp = fp->f_filef) { 10111541Srgrimes if (buflen < sizeof(struct file)) { 10121541Srgrimes *sizep = where - start; 10131541Srgrimes return (ENOMEM); 10141541Srgrimes } 10153308Sphk error = copyout((caddr_t)fp, where, sizeof (struct file)); 10163308Sphk if (error) 10171541Srgrimes return (error); 10181541Srgrimes buflen -= sizeof(struct file); 10191541Srgrimes where += sizeof(struct file); 10201541Srgrimes } 10211541Srgrimes *sizep = where - start; 10221541Srgrimes return (0); 10231541Srgrimes} 10241541Srgrimes 10251541Srgrimes/* 10261541Srgrimes * try over estimating by 5 procs 10271541Srgrimes */ 10281541Srgrimes#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 10291541Srgrimes 10301549Srgrimesint 10311541Srgrimessysctl_doproc(name, namelen, where, sizep) 10321541Srgrimes int *name; 10331541Srgrimes u_int namelen; 10341541Srgrimes char *where; 10351541Srgrimes size_t *sizep; 10361541Srgrimes{ 10371541Srgrimes register struct proc *p; 10381541Srgrimes register struct kinfo_proc *dp = (struct kinfo_proc *)where; 10391541Srgrimes register int needed = 0; 10401541Srgrimes int buflen = where != NULL ? *sizep : 0; 10411541Srgrimes int doingzomb; 10421541Srgrimes struct eproc eproc; 10431541Srgrimes int error = 0; 10441541Srgrimes 10451541Srgrimes if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 10461541Srgrimes return (EINVAL); 10471541Srgrimes p = (struct proc *)allproc; 10481541Srgrimes doingzomb = 0; 10491541Srgrimesagain: 10501541Srgrimes for (; p != NULL; p = p->p_next) { 10511541Srgrimes /* 10521541Srgrimes * Skip embryonic processes. 10531541Srgrimes */ 10541541Srgrimes if (p->p_stat == SIDL) 10551541Srgrimes continue; 10561541Srgrimes /* 10571541Srgrimes * TODO - make more efficient (see notes below). 10581541Srgrimes * do by session. 10591541Srgrimes */ 10601541Srgrimes switch (name[0]) { 10611541Srgrimes 10621541Srgrimes case KERN_PROC_PID: 10631541Srgrimes /* could do this with just a lookup */ 10641541Srgrimes if (p->p_pid != (pid_t)name[1]) 10651541Srgrimes continue; 10661541Srgrimes break; 10671541Srgrimes 10681541Srgrimes case KERN_PROC_PGRP: 10691541Srgrimes /* could do this by traversing pgrp */ 10705260Sdg if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1]) 10711541Srgrimes continue; 10721541Srgrimes break; 10731541Srgrimes 10741541Srgrimes case KERN_PROC_TTY: 10751541Srgrimes if ((p->p_flag & P_CONTROLT) == 0 || 10765260Sdg p->p_session == NULL || 10771541Srgrimes p->p_session->s_ttyp == NULL || 10781541Srgrimes p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 10791541Srgrimes continue; 10801541Srgrimes break; 10811541Srgrimes 10821541Srgrimes case KERN_PROC_UID: 10835260Sdg if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1]) 10841541Srgrimes continue; 10851541Srgrimes break; 10861541Srgrimes 10871541Srgrimes case KERN_PROC_RUID: 10885260Sdg if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1]) 10891541Srgrimes continue; 10901541Srgrimes break; 10911541Srgrimes } 10921541Srgrimes if (buflen >= sizeof(struct kinfo_proc)) { 10931541Srgrimes fill_eproc(p, &eproc); 10948876Srgrimes error = copyout((caddr_t)p, &dp->kp_proc, 10953308Sphk sizeof(struct proc)); 10963308Sphk if (error) 10971541Srgrimes return (error); 10983308Sphk error = copyout((caddr_t)&eproc, &dp->kp_eproc, 10993308Sphk sizeof(eproc)); 11003308Sphk if (error) 11011541Srgrimes return (error); 11021541Srgrimes dp++; 11031541Srgrimes buflen -= sizeof(struct kinfo_proc); 11041541Srgrimes } 11051541Srgrimes needed += sizeof(struct kinfo_proc); 11061541Srgrimes } 11071541Srgrimes if (doingzomb == 0) { 11081541Srgrimes p = zombproc; 11091541Srgrimes doingzomb++; 11101541Srgrimes goto again; 11111541Srgrimes } 11121541Srgrimes if (where != NULL) { 11131541Srgrimes *sizep = (caddr_t)dp - where; 11141541Srgrimes if (needed > *sizep) 11151541Srgrimes return (ENOMEM); 11161541Srgrimes } else { 11171541Srgrimes needed += KERN_PROCSLOP; 11181541Srgrimes *sizep = needed; 11191541Srgrimes } 11201541Srgrimes return (0); 11211541Srgrimes} 11221541Srgrimes 11231541Srgrimes/* 11241541Srgrimes * Fill in an eproc structure for the specified process. 11251541Srgrimes */ 11261541Srgrimesvoid 11271541Srgrimesfill_eproc(p, ep) 11281541Srgrimes register struct proc *p; 11291541Srgrimes register struct eproc *ep; 11301541Srgrimes{ 11311541Srgrimes register struct tty *tp; 11321541Srgrimes 11335260Sdg bzero(ep, sizeof(*ep)); 11345260Sdg 11351541Srgrimes ep->e_paddr = p; 11369747Sdg if (p->p_cred) { 11375260Sdg ep->e_pcred = *p->p_cred; 11389747Sdg if (p->p_ucred) 11399747Sdg ep->e_ucred = *p->p_ucred; 11409747Sdg } 11419747Sdg if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) { 11421541Srgrimes register struct vmspace *vm = p->p_vmspace; 11431541Srgrimes 11441541Srgrimes#ifdef pmap_resident_count 11451541Srgrimes ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/ 11461541Srgrimes#else 11471541Srgrimes ep->e_vm.vm_rssize = vm->vm_rssize; 11481541Srgrimes#endif 11491541Srgrimes ep->e_vm.vm_tsize = vm->vm_tsize; 11501541Srgrimes ep->e_vm.vm_dsize = vm->vm_dsize; 11511541Srgrimes ep->e_vm.vm_ssize = vm->vm_ssize; 11521541Srgrimes#ifndef sparc 11531541Srgrimes ep->e_vm.vm_pmap = vm->vm_pmap; 11541541Srgrimes#endif 11551541Srgrimes } 11561541Srgrimes if (p->p_pptr) 11571541Srgrimes ep->e_ppid = p->p_pptr->p_pid; 11585260Sdg if (p->p_pgrp) { 11595260Sdg ep->e_sess = p->p_pgrp->pg_session; 11605260Sdg ep->e_pgid = p->p_pgrp->pg_id; 11615260Sdg ep->e_jobc = p->p_pgrp->pg_jobc; 11625260Sdg } 11631541Srgrimes if ((p->p_flag & P_CONTROLT) && 11645260Sdg (ep->e_sess != NULL) && 11655260Sdg ((tp = ep->e_sess->s_ttyp) != NULL)) { 11661541Srgrimes ep->e_tdev = tp->t_dev; 11671541Srgrimes ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 11681541Srgrimes ep->e_tsess = tp->t_session; 11691541Srgrimes } else 11701541Srgrimes ep->e_tdev = NODEV; 11718876Srgrimes if (ep->e_sess && ep->e_sess->s_ttyvp) 11725260Sdg ep->e_flag = EPROC_CTTY; 11731541Srgrimes if (SESS_LEADER(p)) 11741541Srgrimes ep->e_flag |= EPROC_SLEADER; 11755260Sdg if (p->p_wmesg) { 11761541Srgrimes strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 11775260Sdg ep->e_wmesg[WMESGLEN] = 0; 11785260Sdg } 11791541Srgrimes} 11801541Srgrimes 11811541Srgrimes#ifdef COMPAT_43 11821541Srgrimes#include <sys/socket.h> 11831541Srgrimes#define KINFO_PROC (0<<8) 11841541Srgrimes#define KINFO_RT (1<<8) 11851541Srgrimes#define KINFO_VNODE (2<<8) 11861541Srgrimes#define KINFO_FILE (3<<8) 11871541Srgrimes#define KINFO_METER (4<<8) 11881541Srgrimes#define KINFO_LOADAVG (5<<8) 11891541Srgrimes#define KINFO_CLOCKRATE (6<<8) 11901541Srgrimes 11919455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 11929455Speter#define KINFO_BSDI_SYSINFO (101<<8) 11939455Speter 11949455Speter/* 11959455Speter * XXX this is bloat, but I hope it's better here than on the potentially 11969455Speter * limited kernel stack... -Peter 11979455Speter */ 11989455Speter 11999455Speterstruct { 12009455Speter int bsdi_machine; /* "i386" on BSD/386 */ 12019455Speter/* ^^^ this is an offset to the string, relative to the struct start */ 12029455Speter char *pad0; 12039455Speter long pad1; 12049455Speter long pad2; 12059455Speter long pad3; 12069455Speter u_long pad4; 12079455Speter u_long pad5; 12089455Speter u_long pad6; 12099455Speter 12109455Speter int bsdi_ostype; /* "BSD/386" on BSD/386 */ 12119455Speter int bsdi_osrelease; /* "1.1" on BSD/386 */ 12129455Speter long pad7; 12139455Speter long pad8; 12149455Speter char *pad9; 12159455Speter 12169455Speter long pad10; 12179455Speter long pad11; 12189455Speter int pad12; 12199455Speter long pad13; 12209455Speter quad_t pad14; 12219455Speter long pad15; 12229455Speter 12239455Speter struct timeval pad16; 12249455Speter /* we dont set this, because BSDI's uname used gethostname() instead */ 12259455Speter int bsdi_hostname; /* hostname on BSD/386 */ 12269455Speter 12279455Speter /* the actual string data is appended here */ 12289455Speter 12299455Speter} bsdi_si; 12309455Speter/* 12319455Speter * this data is appended to the end of the bsdi_si structure during copyout. 12329455Speter * The "char *" offsets are relative to the base of the bsdi_si struct. 12339455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 12349455Speter * should not exceed the length of the buffer here... (or else!! :-) 12359455Speter */ 12369455Speterchar bsdi_strings[80]; /* It had better be less than this! */ 12379455Speter 123812221Sbde#ifndef _SYS_SYSPROTO_H_ 12391541Srgrimesstruct getkerninfo_args { 12401541Srgrimes int op; 12411541Srgrimes char *where; 12421541Srgrimes int *size; 12431541Srgrimes int arg; 12441541Srgrimes}; 124512221Sbde#endif 12461541Srgrimes 12471549Srgrimesint 12481541Srgrimesogetkerninfo(p, uap, retval) 12491541Srgrimes struct proc *p; 12501541Srgrimes register struct getkerninfo_args *uap; 12511541Srgrimes int *retval; 12521541Srgrimes{ 125312171Sphk int error, name[6]; 12541541Srgrimes u_int size; 12551541Srgrimes 12561541Srgrimes switch (uap->op & 0xff00) { 12571541Srgrimes 12581541Srgrimes case KINFO_RT: 125912171Sphk name[0] = CTL_NET; 126012171Sphk name[1] = PF_ROUTE; 126112171Sphk name[2] = 0; 126212171Sphk name[3] = (uap->op & 0xff0000) >> 16; 126312171Sphk name[4] = uap->op & 0xff; 126412171Sphk name[5] = uap->arg; 126512171Sphk error = userland_sysctl(p, name, 6, uap->where, uap->size, 126612171Sphk 0, 0, 0, 0); 12671541Srgrimes break; 12681541Srgrimes 12691541Srgrimes case KINFO_VNODE: 127012171Sphk name[0] = CTL_KERN; 127112171Sphk name[1] = KERN_VNODE; 127212171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 127312171Sphk 0, 0, 0, 0); 12741541Srgrimes break; 12751541Srgrimes 12761541Srgrimes case KINFO_PROC: 127712171Sphk name[0] = CTL_KERN; 127812171Sphk name[1] = KERN_PROC; 127912171Sphk name[2] = uap->op & 0xff; 128012171Sphk name[3] = uap->arg; 128112171Sphk error = userland_sysctl(p, name, 4, uap->where, uap->size, 128212171Sphk 0, 0, 0, 0); 12831541Srgrimes break; 12841541Srgrimes 12851541Srgrimes case KINFO_FILE: 128612171Sphk name[0] = CTL_KERN; 128712171Sphk name[1] = KERN_FILE; 128812171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 128912171Sphk 0, 0, 0, 0); 12901541Srgrimes break; 12911541Srgrimes 12921541Srgrimes case KINFO_METER: 129312171Sphk name[0] = CTL_VM; 129412171Sphk name[1] = VM_METER; 129512171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 129612171Sphk 0, 0, 0, 0); 12971541Srgrimes break; 12981541Srgrimes 12991541Srgrimes case KINFO_LOADAVG: 130012171Sphk name[0] = CTL_VM; 130112171Sphk name[1] = VM_LOADAVG; 130212171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 130312171Sphk 0, 0, 0, 0); 13041541Srgrimes break; 13051541Srgrimes 13061541Srgrimes case KINFO_CLOCKRATE: 130712171Sphk name[0] = CTL_KERN; 130812171Sphk name[1] = KERN_CLOCKRATE; 130912171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 131012171Sphk 0, 0, 0, 0); 13111541Srgrimes break; 13121541Srgrimes 13139455Speter case KINFO_BSDI_SYSINFO: { 13149455Speter /* 13159455Speter * this is pretty crude, but it's just enough for uname() 13169455Speter * from BSDI's 1.x libc to work. 13179455Speter * 13189455Speter * In particular, it doesn't return the same results when 13199455Speter * the supplied buffer is too small. BSDI's version apparently 13209455Speter * will return the amount copied, and set the *size to how 13219455Speter * much was needed. The emulation framework here isn't capable 13229455Speter * of that, so we just set both to the amount copied. 13239455Speter * BSDI's 2.x product apparently fails with ENOMEM in this 13249455Speter * scenario. 13259455Speter */ 13269455Speter 13279455Speter u_int needed; 13289455Speter u_int left; 13299455Speter char *s; 13309455Speter 13319455Speter bzero((char *)&bsdi_si, sizeof(bsdi_si)); 13329455Speter bzero(bsdi_strings, sizeof(bsdi_strings)); 13339455Speter 13349455Speter s = bsdi_strings; 13359455Speter 13369455Speter bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 13379455Speter strcpy(s, ostype); 13389455Speter s += strlen(s) + 1; 13399455Speter 13409455Speter bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 13419455Speter strcpy(s, osrelease); 13429455Speter s += strlen(s) + 1; 13439455Speter 13449455Speter bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 13459455Speter strcpy(s, machine); 13469455Speter s += strlen(s) + 1; 13479455Speter 13489455Speter needed = sizeof(bsdi_si) + (s - bsdi_strings); 13499455Speter 13509455Speter if (uap->where == NULL) { 13519455Speter /* process is asking how much buffer to supply.. */ 13529455Speter size = needed; 13539455Speter error = 0; 13549455Speter break; 13559455Speter } 13569455Speter 13579455Speter 13589455Speter /* if too much buffer supplied, trim it down */ 13599455Speter if (size > needed) 13609455Speter size = needed; 13619455Speter 13629455Speter /* how much of the buffer is remaining */ 13639455Speter left = size; 13649455Speter 13659455Speter if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 13669455Speter break; 13679455Speter 13689455Speter /* is there any point in continuing? */ 13699455Speter if (left > sizeof(bsdi_si)) { 13709455Speter left -= sizeof(bsdi_si); 13719455Speter error = copyout(&bsdi_strings, 13729455Speter uap->where + sizeof(bsdi_si), left); 13739455Speter } 13749455Speter break; 13759455Speter } 13769455Speter 13771541Srgrimes default: 13781541Srgrimes return (EOPNOTSUPP); 13791541Srgrimes } 13801541Srgrimes if (error) 13811541Srgrimes return (error); 13821541Srgrimes *retval = size; 13831541Srgrimes if (uap->size) 13841541Srgrimes error = copyout((caddr_t)&size, (caddr_t)uap->size, 13851541Srgrimes sizeof(size)); 13861541Srgrimes return (error); 13871541Srgrimes} 13881541Srgrimes#endif /* COMPAT_43 */ 1389