kern_sysctl.c revision 12243
19663SMark.Logan@Sun.COM/*- 29663SMark.Logan@Sun.COM * Copyright (c) 1982, 1986, 1989, 1993 39663SMark.Logan@Sun.COM * The Regents of the University of California. All rights reserved. 49663SMark.Logan@Sun.COM * 59663SMark.Logan@Sun.COM * This code is derived from software contributed to Berkeley by 69663SMark.Logan@Sun.COM * Mike Karels at Berkeley Software Design, Inc. 79663SMark.Logan@Sun.COM * 89663SMark.Logan@Sun.COM * Redistribution and use in source and binary forms, with or without 99663SMark.Logan@Sun.COM * modification, are permitted provided that the following conditions 109663SMark.Logan@Sun.COM * are met: 119663SMark.Logan@Sun.COM * 1. Redistributions of source code must retain the above copyright 129663SMark.Logan@Sun.COM * notice, this list of conditions and the following disclaimer. 139663SMark.Logan@Sun.COM * 2. Redistributions in binary form must reproduce the above copyright 149663SMark.Logan@Sun.COM * notice, this list of conditions and the following disclaimer in the 159663SMark.Logan@Sun.COM * documentation and/or other materials provided with the distribution. 169663SMark.Logan@Sun.COM * 3. All advertising materials mentioning features or use of this software 179663SMark.Logan@Sun.COM * must display the following acknowledgement: 189663SMark.Logan@Sun.COM * This product includes software developed by the University of 199663SMark.Logan@Sun.COM * California, Berkeley and its contributors. 209663SMark.Logan@Sun.COM * 4. Neither the name of the University nor the names of its contributors 219663SMark.Logan@Sun.COM * may be used to endorse or promote products derived from this software 229663SMark.Logan@Sun.COM * without specific prior written permission. 239663SMark.Logan@Sun.COM * 249663SMark.Logan@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 259663SMark.Logan@Sun.COM * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 269663SMark.Logan@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 279663SMark.Logan@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 289663SMark.Logan@Sun.COM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 299663SMark.Logan@Sun.COM * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 309663SMark.Logan@Sun.COM * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 319663SMark.Logan@Sun.COM * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 329663SMark.Logan@Sun.COM * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 339663SMark.Logan@Sun.COM * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 349663SMark.Logan@Sun.COM * SUCH DAMAGE. 359663SMark.Logan@Sun.COM * 369663SMark.Logan@Sun.COM * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 379663SMark.Logan@Sun.COM * $Id: kern_sysctl.c,v 1.37 1995/11/12 06:43:01 bde Exp $ 389663SMark.Logan@Sun.COM */ 399663SMark.Logan@Sun.COM 409663SMark.Logan@Sun.COM/* 419663SMark.Logan@Sun.COM * sysctl system call. 429663SMark.Logan@Sun.COM */ 439663SMark.Logan@Sun.COM 449663SMark.Logan@Sun.COM#include <sys/param.h> 459663SMark.Logan@Sun.COM#include <sys/systm.h> 469663SMark.Logan@Sun.COM#include <sys/sysproto.h> 479663SMark.Logan@Sun.COM#include <sys/kernel.h> 489663SMark.Logan@Sun.COM#include <sys/malloc.h> 499663SMark.Logan@Sun.COM#include <sys/proc.h> 509663SMark.Logan@Sun.COM#include <sys/file.h> 519663SMark.Logan@Sun.COM#include <sys/vnode.h> 529663SMark.Logan@Sun.COM#include <sys/unistd.h> 539663SMark.Logan@Sun.COM#include <sys/buf.h> 549663SMark.Logan@Sun.COM#include <sys/ioctl.h> 559663SMark.Logan@Sun.COM#include <sys/tty.h> 569663SMark.Logan@Sun.COM#include <sys/conf.h> 579663SMark.Logan@Sun.COM#include <vm/vm.h> 589663SMark.Logan@Sun.COM#include <sys/sysctl.h> 599663SMark.Logan@Sun.COM#include <sys/user.h> 6010214SMark.Logan@Sun.COM 619663SMark.Logan@Sun.COMextern struct linker_set sysctl_; 629663SMark.Logan@Sun.COM 639663SMark.Logan@Sun.COM/* BEGIN_MIB */ 649663SMark.Logan@Sun.COMSYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, 659663SMark.Logan@Sun.COM "Sysctl internal magic"); 669663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, 679663SMark.Logan@Sun.COM "High kernel, proc, limits &c"); 689663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, 699663SMark.Logan@Sun.COM "Virtual memory"); 709663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_FS, fs, CTLFLAG_RW, 0, 719663SMark.Logan@Sun.COM "File system"); 729663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, 739663SMark.Logan@Sun.COM "Network, (see socket.h)"); 749663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, 759663SMark.Logan@Sun.COM "Debugging"); 769663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, 779663SMark.Logan@Sun.COM "hardware"); 789663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, 799663SMark.Logan@Sun.COM "machine dependent"); 809663SMark.Logan@Sun.COMSYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, 819663SMark.Logan@Sun.COM "user-level"); 829663SMark.Logan@Sun.COM 839663SMark.Logan@Sun.COMSYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, ""); 849663SMark.Logan@Sun.COM 859663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, ""); 869663SMark.Logan@Sun.COM 879663SMark.Logan@Sun.COMSYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, ""); 889663SMark.Logan@Sun.COM 899663SMark.Logan@Sun.COMSYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, ""); 909663SMark.Logan@Sun.COM 919663SMark.Logan@Sun.COMextern int osreldate; 929663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, ""); 939663SMark.Logan@Sun.COM 949663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, ""); 959663SMark.Logan@Sun.COM 969663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, ""); 979663SMark.Logan@Sun.COM 989663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, 999663SMark.Logan@Sun.COM CTLFLAG_RD, &maxprocperuid, 0, ""); 1009663SMark.Logan@Sun.COM 1019663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, 1029663SMark.Logan@Sun.COM CTLFLAG_RD, &maxfilesperproc, 0, ""); 1039663SMark.Logan@Sun.COM 1049663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, ""); 1059663SMark.Logan@Sun.COM 1069663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, ""); 1079663SMark.Logan@Sun.COM 1089663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, ""); 1099663SMark.Logan@Sun.COM 1109663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, ""); 1119663SMark.Logan@Sun.COM 1129663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, ""); 1139663SMark.Logan@Sun.COM 1149663SMark.Logan@Sun.COM#ifdef _POSIX_SAVED_IDS 1159663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, ""); 1169663SMark.Logan@Sun.COM#else 1179663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, ""); 1189663SMark.Logan@Sun.COM#endif 1199663SMark.Logan@Sun.COM 1209663SMark.Logan@Sun.COMchar kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ 1219663SMark.Logan@Sun.COM 1229663SMark.Logan@Sun.COMSYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, 1239663SMark.Logan@Sun.COM CTLFLAG_RW, kernelname, sizeof kernelname, ""); 1249663SMark.Logan@Sun.COM 1259663SMark.Logan@Sun.COMSYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, 1269663SMark.Logan@Sun.COM CTLFLAG_RW, &boottime, timeval, ""); 1279663SMark.Logan@Sun.COM 1289663SMark.Logan@Sun.COMSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); 1299663SMark.Logan@Sun.COM 1309663SMark.Logan@Sun.COMSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); 1319663SMark.Logan@Sun.COM 1329663SMark.Logan@Sun.COMSYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, ""); 1339663SMark.Logan@Sun.COM 1349663SMark.Logan@Sun.COMSYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, ""); 1359663SMark.Logan@Sun.COM 1369663SMark.Logan@Sun.COMSYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, ""); 1379663SMark.Logan@Sun.COM 1389663SMark.Logan@Sun.COM/* END_MIB */ 1399663SMark.Logan@Sun.COM 1409663SMark.Logan@Sun.COMextern int vfs_update_wakeup; 1419663SMark.Logan@Sun.COMextern int vfs_update_interval; 1429663SMark.Logan@Sun.COMstatic int 1439663SMark.Logan@Sun.COMsysctl_kern_updateinterval SYSCTL_HANDLER_ARGS 1449663SMark.Logan@Sun.COM{ 1459663SMark.Logan@Sun.COM int error = sysctl_handle_int(oidp, 1469663SMark.Logan@Sun.COM oidp->oid_arg1, oidp->oid_arg2, req); 1479663SMark.Logan@Sun.COM if (!error) 1489663SMark.Logan@Sun.COM wakeup(&vfs_update_wakeup); 1499663SMark.Logan@Sun.COM return error; 1509663SMark.Logan@Sun.COM} 1519663SMark.Logan@Sun.COM 1529663SMark.Logan@Sun.COMSYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW, 1539663SMark.Logan@Sun.COM &vfs_update_interval, 0, sysctl_kern_updateinterval, ""); 1549663SMark.Logan@Sun.COM 1559663SMark.Logan@Sun.COM 1569663SMark.Logan@Sun.COMchar hostname[MAXHOSTNAMELEN]; 1579663SMark.Logan@Sun.COMint hostnamelen; 1589663SMark.Logan@Sun.COMstatic int 1599663SMark.Logan@Sun.COMsysctl_kern_hostname SYSCTL_HANDLER_ARGS 1609663SMark.Logan@Sun.COM{ 1619663SMark.Logan@Sun.COM int error = sysctl_handle_string(oidp, 1629663SMark.Logan@Sun.COM oidp->oid_arg1, oidp->oid_arg2, req); 1639663SMark.Logan@Sun.COM if (req->newptr && (error == 0 || error == ENOMEM)) 1649663SMark.Logan@Sun.COM hostnamelen = req->newlen; 1659663SMark.Logan@Sun.COM return error; 1669663SMark.Logan@Sun.COM} 1679663SMark.Logan@Sun.COM 1689663SMark.Logan@Sun.COMSYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW, 1699663SMark.Logan@Sun.COM &hostname, sizeof(hostname), sysctl_kern_hostname, ""); 1709663SMark.Logan@Sun.COM 1719663SMark.Logan@Sun.COMstatic int 1729663SMark.Logan@Sun.COMsysctl_order_cmp(const void *a, const void *b) 1739663SMark.Logan@Sun.COM{ 1749663SMark.Logan@Sun.COM const struct sysctl_oid **pa, **pb; 1759663SMark.Logan@Sun.COM 1769663SMark.Logan@Sun.COM pa = (const struct sysctl_oid **)a; 1779663SMark.Logan@Sun.COM pb = (const struct sysctl_oid **)b; 1789663SMark.Logan@Sun.COM if (*pa == NULL) 1799663SMark.Logan@Sun.COM return (1); 1809663SMark.Logan@Sun.COM if (*pb == NULL) 1819663SMark.Logan@Sun.COM return (-1); 1829663SMark.Logan@Sun.COM return ((*pa)->oid_number - (*pb)->oid_number); 1839663SMark.Logan@Sun.COM} 1849663SMark.Logan@Sun.COM 1859663SMark.Logan@Sun.COMstatic void 1869663SMark.Logan@Sun.COMsysctl_order(void *arg) 1879663SMark.Logan@Sun.COM{ 1889663SMark.Logan@Sun.COM int j; 1899663SMark.Logan@Sun.COM struct linker_set *l = (struct linker_set *) arg; 1909663SMark.Logan@Sun.COM struct sysctl_oid **oidpp; 1919663SMark.Logan@Sun.COM 1929663SMark.Logan@Sun.COM j = l->ls_length; 1939663SMark.Logan@Sun.COM oidpp = (struct sysctl_oid **) l->ls_items; 1949663SMark.Logan@Sun.COM for (; j--; oidpp++) { 1959663SMark.Logan@Sun.COM if (!*oidpp) 1969663SMark.Logan@Sun.COM continue; 1979663SMark.Logan@Sun.COM if ((*oidpp)->oid_arg1 == arg) { 1989663SMark.Logan@Sun.COM *oidpp = 0; 1999663SMark.Logan@Sun.COM continue; 2009663SMark.Logan@Sun.COM } 2019663SMark.Logan@Sun.COM if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 2029663SMark.Logan@Sun.COM if (!(*oidpp)->oid_handler) 2039663SMark.Logan@Sun.COM sysctl_order((*oidpp)->oid_arg1); 2049663SMark.Logan@Sun.COM } 2059663SMark.Logan@Sun.COM qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 2069663SMark.Logan@Sun.COM sysctl_order_cmp); 2079663SMark.Logan@Sun.COM} 2089663SMark.Logan@Sun.COM 2099663SMark.Logan@Sun.COMSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_); 2109663SMark.Logan@Sun.COM 2119663SMark.Logan@Sun.COMstatic void 2129663SMark.Logan@Sun.COMsysctl_sysctl_debug_dump_node(struct linker_set *l, int i) 2139663SMark.Logan@Sun.COM{ 2149663SMark.Logan@Sun.COM int j, k; 2159663SMark.Logan@Sun.COM struct sysctl_oid **oidpp; 2169663SMark.Logan@Sun.COM 2179663SMark.Logan@Sun.COM j = l->ls_length; 2189663SMark.Logan@Sun.COM oidpp = (struct sysctl_oid **) l->ls_items; 2199663SMark.Logan@Sun.COM for (; j--; oidpp++) { 2209663SMark.Logan@Sun.COM 2219663SMark.Logan@Sun.COM if (!*oidpp) 2229663SMark.Logan@Sun.COM continue; 2239663SMark.Logan@Sun.COM 2249663SMark.Logan@Sun.COM for (k=0; k<i; k++) 2259663SMark.Logan@Sun.COM printf(" "); 2269663SMark.Logan@Sun.COM 2279663SMark.Logan@Sun.COM if ((*oidpp)->oid_number > 100) { 2289663SMark.Logan@Sun.COM printf("Junk! %p # %d %s k %x a1 %p a2 %x h %p\n", 2299663SMark.Logan@Sun.COM *oidpp, 2309663SMark.Logan@Sun.COM (*oidpp)->oid_number, (*oidpp)->oid_name, 2319663SMark.Logan@Sun.COM (*oidpp)->oid_kind, (*oidpp)->oid_arg1, 2329663SMark.Logan@Sun.COM (*oidpp)->oid_arg2, (*oidpp)->oid_handler); 2339663SMark.Logan@Sun.COM continue; 2349663SMark.Logan@Sun.COM } 2359663SMark.Logan@Sun.COM printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 2369663SMark.Logan@Sun.COM 2379663SMark.Logan@Sun.COM printf("%c%c", 2389663SMark.Logan@Sun.COM (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 2399663SMark.Logan@Sun.COM (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 2409663SMark.Logan@Sun.COM 2419663SMark.Logan@Sun.COM switch ((*oidpp)->oid_kind & CTLTYPE) { 2429663SMark.Logan@Sun.COM case CTLTYPE_NODE: 2439663SMark.Logan@Sun.COM if ((*oidpp)->oid_handler) { 2449663SMark.Logan@Sun.COM printf(" Node(proc)\n"); 2459663SMark.Logan@Sun.COM } else { 2469663SMark.Logan@Sun.COM printf(" Node\n"); 2479663SMark.Logan@Sun.COM sysctl_sysctl_debug_dump_node( 2489663SMark.Logan@Sun.COM (*oidpp)->oid_arg1, i+2); 2499663SMark.Logan@Sun.COM } 2509663SMark.Logan@Sun.COM break; 2519663SMark.Logan@Sun.COM case CTLTYPE_INT: printf(" Int\n"); break; 2529663SMark.Logan@Sun.COM case CTLTYPE_STRING: printf(" String\n"); break; 2539663SMark.Logan@Sun.COM case CTLTYPE_QUAD: printf(" Quad\n"); break; 2549663SMark.Logan@Sun.COM case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 2559663SMark.Logan@Sun.COM default: printf("\n"); 2569663SMark.Logan@Sun.COM } 2579663SMark.Logan@Sun.COM 2589663SMark.Logan@Sun.COM } 2599663SMark.Logan@Sun.COM} 2609663SMark.Logan@Sun.COM 2619663SMark.Logan@Sun.COM 2629663SMark.Logan@Sun.COMstatic int 2639663SMark.Logan@Sun.COMsysctl_sysctl_debug SYSCTL_HANDLER_ARGS 2649663SMark.Logan@Sun.COM{ 2659663SMark.Logan@Sun.COM sysctl_sysctl_debug_dump_node(&sysctl_, 0); 2669663SMark.Logan@Sun.COM return ENOENT; 2679663SMark.Logan@Sun.COM} 2689663SMark.Logan@Sun.COM 2699663SMark.Logan@Sun.COMSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 2709663SMark.Logan@Sun.COM 0, 0, sysctl_sysctl_debug, ""); 2719663SMark.Logan@Sun.COM 2729663SMark.Logan@Sun.COMchar domainname[MAXHOSTNAMELEN]; 2739663SMark.Logan@Sun.COMint domainnamelen; 2749663SMark.Logan@Sun.COMstatic int 2759663SMark.Logan@Sun.COMsysctl_kern_domainname SYSCTL_HANDLER_ARGS 2769663SMark.Logan@Sun.COM{ 2779663SMark.Logan@Sun.COM int error = sysctl_handle_string(oidp, 2789663SMark.Logan@Sun.COM oidp->oid_arg1, oidp->oid_arg2, req); 2799663SMark.Logan@Sun.COM if (req->newptr && (error == 0 || error == ENOMEM)) 2809663SMark.Logan@Sun.COM domainnamelen = req->newlen; 2819663SMark.Logan@Sun.COM return error; 2829663SMark.Logan@Sun.COM} 2839663SMark.Logan@Sun.COM 2849663SMark.Logan@Sun.COMSYSCTL_PROC(_kern, KERN_DOMAINNAME, domainname, CTLTYPE_STRING|CTLFLAG_RW, 2859663SMark.Logan@Sun.COM &domainname, sizeof(domainname), sysctl_kern_domainname, ""); 2869663SMark.Logan@Sun.COM 2879663SMark.Logan@Sun.COMlong hostid; 2889663SMark.Logan@Sun.COM/* Some trouble here, if sizeof (int) != sizeof (long) */ 2899663SMark.Logan@Sun.COMSYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, ""); 2909663SMark.Logan@Sun.COM 2919663SMark.Logan@Sun.COM/* 2929663SMark.Logan@Sun.COM * Handle an integer, signed or unsigned. 2939663SMark.Logan@Sun.COM * Two cases: 2949663SMark.Logan@Sun.COM * a variable: point arg1 at it. 2959663SMark.Logan@Sun.COM * a constant: pass it in arg2. 2969663SMark.Logan@Sun.COM */ 2979663SMark.Logan@Sun.COM 2989663SMark.Logan@Sun.COMint 2999663SMark.Logan@Sun.COMsysctl_handle_int SYSCTL_HANDLER_ARGS 3009663SMark.Logan@Sun.COM{ 3019663SMark.Logan@Sun.COM int error = 0; 3029663SMark.Logan@Sun.COM 3039663SMark.Logan@Sun.COM if (arg1) 3049663SMark.Logan@Sun.COM error = SYSCTL_OUT(req, arg1, sizeof(int)); 3059663SMark.Logan@Sun.COM else if (arg2) 3069663SMark.Logan@Sun.COM error = SYSCTL_OUT(req, &arg2, sizeof(int)); 3079663SMark.Logan@Sun.COM 3089663SMark.Logan@Sun.COM if (error || !req->newptr) 3099663SMark.Logan@Sun.COM return (error); 3109663SMark.Logan@Sun.COM 3119663SMark.Logan@Sun.COM if (!arg1) 3129663SMark.Logan@Sun.COM error = EPERM; 3139663SMark.Logan@Sun.COM else 3149663SMark.Logan@Sun.COM error = SYSCTL_IN(req, arg1, sizeof(int)); 3159663SMark.Logan@Sun.COM return (error); 3169663SMark.Logan@Sun.COM} 3179663SMark.Logan@Sun.COM 3189663SMark.Logan@Sun.COM/* 3199663SMark.Logan@Sun.COM * Handle our generic '\0' terminated 'C' string. 3209663SMark.Logan@Sun.COM * Two cases: 3219663SMark.Logan@Sun.COM * a variable string: point arg1 at it, arg2 is max length. 3229663SMark.Logan@Sun.COM * a constant string: point arg1 at it, arg2 is zero. 3239663SMark.Logan@Sun.COM */ 3249663SMark.Logan@Sun.COM 3259663SMark.Logan@Sun.COMint 3269663SMark.Logan@Sun.COMsysctl_handle_string SYSCTL_HANDLER_ARGS 3279663SMark.Logan@Sun.COM{ 3289663SMark.Logan@Sun.COM int error=0; 3299663SMark.Logan@Sun.COM 3309663SMark.Logan@Sun.COM if (arg2) 3319663SMark.Logan@Sun.COM error = SYSCTL_OUT(req, arg1, arg2); 3329663SMark.Logan@Sun.COM else 3339663SMark.Logan@Sun.COM error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1); 3349663SMark.Logan@Sun.COM 3359663SMark.Logan@Sun.COM if (error || !req->newptr) 3369663SMark.Logan@Sun.COM return (error); 3379663SMark.Logan@Sun.COM 3389663SMark.Logan@Sun.COM if ((req->newlen - req->newidx) > arg2) { 3399663SMark.Logan@Sun.COM error = E2BIG; 3409663SMark.Logan@Sun.COM } else { 3419663SMark.Logan@Sun.COM arg2 = (req->newlen - req->newidx); 3429663SMark.Logan@Sun.COM error = SYSCTL_IN(req, arg1, arg2); 3439663SMark.Logan@Sun.COM ((char *)arg1)[arg2] = '\0'; 3449663SMark.Logan@Sun.COM } 3459663SMark.Logan@Sun.COM 3469663SMark.Logan@Sun.COM return (error); 3479663SMark.Logan@Sun.COM} 3489663SMark.Logan@Sun.COM 3499663SMark.Logan@Sun.COM/* 3509663SMark.Logan@Sun.COM * Handle any kind of opaque data. 3519663SMark.Logan@Sun.COM * arg1 points to it, arg2 is the size. 3529663SMark.Logan@Sun.COM */ 3539663SMark.Logan@Sun.COM 3549663SMark.Logan@Sun.COMint 3559663SMark.Logan@Sun.COMsysctl_handle_opaque SYSCTL_HANDLER_ARGS 3569663SMark.Logan@Sun.COM{ 3579663SMark.Logan@Sun.COM int error; 3589663SMark.Logan@Sun.COM 3599663SMark.Logan@Sun.COM error = SYSCTL_OUT(req, arg1, arg2); 3609663SMark.Logan@Sun.COM 3619663SMark.Logan@Sun.COM if (error || !req->newptr) 3629663SMark.Logan@Sun.COM return (error); 3639663SMark.Logan@Sun.COM 3649663SMark.Logan@Sun.COM error = SYSCTL_IN(req, arg1, arg2); 3659663SMark.Logan@Sun.COM 3669663SMark.Logan@Sun.COM return (error); 3679663SMark.Logan@Sun.COM} 3689663SMark.Logan@Sun.COM 3699663SMark.Logan@Sun.COMint 3709663SMark.Logan@Sun.COMsysctl_old_kernel(struct sysctl_req *req, void *p, int l) 3719663SMark.Logan@Sun.COM{ 3729663SMark.Logan@Sun.COM int i = min(req->oldlen - req->oldidx, l); 3739663SMark.Logan@Sun.COM if (i) { 3749663SMark.Logan@Sun.COM bcopy(p, req->oldptr + req->oldidx, i); 3759663SMark.Logan@Sun.COM req->oldidx += i; 3769663SMark.Logan@Sun.COM } 3779663SMark.Logan@Sun.COM if (i != l) 3789663SMark.Logan@Sun.COM return (ENOMEM); 3799663SMark.Logan@Sun.COM else 3809663SMark.Logan@Sun.COM return (0); 3819663SMark.Logan@Sun.COM 3829663SMark.Logan@Sun.COM} 3839663SMark.Logan@Sun.COM 3849663SMark.Logan@Sun.COMint 3859663SMark.Logan@Sun.COMsysctl_new_kernel(struct sysctl_req *req, void *p, int l) 3869663SMark.Logan@Sun.COM{ 3879663SMark.Logan@Sun.COM int i = req->newlen - req->newidx; 3889663SMark.Logan@Sun.COM if (i < l) 3899663SMark.Logan@Sun.COM return (EINVAL); 3909663SMark.Logan@Sun.COM bcopy(req->newptr + req->newidx, p, l); 3919663SMark.Logan@Sun.COM req->newidx += l; 3929663SMark.Logan@Sun.COM return (0); 3939663SMark.Logan@Sun.COM} 3949663SMark.Logan@Sun.COM 3959663SMark.Logan@Sun.COMint 3969663SMark.Logan@Sun.COMsysctl_old_user(struct sysctl_req *req, void *p, int l) 3979663SMark.Logan@Sun.COM{ 3989663SMark.Logan@Sun.COM int error , i = min(req->oldlen - req->oldidx, l); 3999663SMark.Logan@Sun.COM 4009663SMark.Logan@Sun.COM error = copyout(p, req->oldptr + req->oldidx, i); 4019663SMark.Logan@Sun.COM req->oldidx += i; 4029663SMark.Logan@Sun.COM if (error) 4039663SMark.Logan@Sun.COM return (error); 4049663SMark.Logan@Sun.COM if (i < l) 4059663SMark.Logan@Sun.COM return (ENOMEM); 4069663SMark.Logan@Sun.COM return (error); 4079663SMark.Logan@Sun.COM} 4089663SMark.Logan@Sun.COM 4099663SMark.Logan@Sun.COMint 4109663SMark.Logan@Sun.COMsysctl_new_user(struct sysctl_req *req, void *p, int l) 4119663SMark.Logan@Sun.COM{ 4129663SMark.Logan@Sun.COM int error, i = req->newlen - req->newidx; 4139663SMark.Logan@Sun.COM if (i < l) 4149663SMark.Logan@Sun.COM return (EINVAL); 4159663SMark.Logan@Sun.COM error = copyin(req->newptr + req->newidx, p, l); 4169663SMark.Logan@Sun.COM req->newidx += l; 4179663SMark.Logan@Sun.COM return (error); 4189663SMark.Logan@Sun.COM} 4199663SMark.Logan@Sun.COM 4209663SMark.Logan@Sun.COM#ifdef DEBUG 4219663SMark.Logan@Sun.COMstatic sysctlfn debug_sysctl; 4229663SMark.Logan@Sun.COM#endif 4239663SMark.Logan@Sun.COM 4249663SMark.Logan@Sun.COM/* 4259663SMark.Logan@Sun.COM * Locking and stats 4269663SMark.Logan@Sun.COM */ 4279663SMark.Logan@Sun.COMstatic struct sysctl_lock { 4289663SMark.Logan@Sun.COM int sl_lock; 4299663SMark.Logan@Sun.COM int sl_want; 4309663SMark.Logan@Sun.COM int sl_locked; 4319663SMark.Logan@Sun.COM} memlock; 4329663SMark.Logan@Sun.COM 4339663SMark.Logan@Sun.COM 4349663SMark.Logan@Sun.COM 4359663SMark.Logan@Sun.COM/* 4369663SMark.Logan@Sun.COM * Traverse our tree, and find the right node, execute whatever it points 4379663SMark.Logan@Sun.COM * at, and return the resulting error code. 4389663SMark.Logan@Sun.COM * We work entirely in kernel-space at this time. 4399663SMark.Logan@Sun.COM */ 4409663SMark.Logan@Sun.COM 4419663SMark.Logan@Sun.COM 4429663SMark.Logan@Sun.COMint 4439663SMark.Logan@Sun.COMsysctl_root SYSCTL_HANDLER_ARGS 4449663SMark.Logan@Sun.COM{ 4459663SMark.Logan@Sun.COM int *name = (int *) arg1; 4469663SMark.Logan@Sun.COM int namelen = arg2; 4479663SMark.Logan@Sun.COM int indx, i, j; 4489663SMark.Logan@Sun.COM struct sysctl_oid **oidpp; 4499663SMark.Logan@Sun.COM struct linker_set *lsp = &sysctl_; 4509663SMark.Logan@Sun.COM 4519663SMark.Logan@Sun.COM j = lsp->ls_length; 4529663SMark.Logan@Sun.COM oidpp = (struct sysctl_oid **) lsp->ls_items; 4539663SMark.Logan@Sun.COM 4549663SMark.Logan@Sun.COM indx = 0; 4559663SMark.Logan@Sun.COM while (j-- && indx < CTL_MAXNAME) { 4569663SMark.Logan@Sun.COM if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 4579663SMark.Logan@Sun.COM indx++; 4589663SMark.Logan@Sun.COM if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 4599663SMark.Logan@Sun.COM if ((*oidpp)->oid_handler) 4609663SMark.Logan@Sun.COM goto found; 4619663SMark.Logan@Sun.COM if (indx == namelen) 4629663SMark.Logan@Sun.COM return ENOENT; 4639663SMark.Logan@Sun.COM lsp = (struct linker_set*)(*oidpp)->oid_arg1; 4649663SMark.Logan@Sun.COM j = lsp->ls_length; 4659663SMark.Logan@Sun.COM oidpp = (struct sysctl_oid **)lsp->ls_items; 4669663SMark.Logan@Sun.COM } else { 4679663SMark.Logan@Sun.COM if (indx != namelen) 4689663SMark.Logan@Sun.COM return EISDIR; 4699663SMark.Logan@Sun.COM goto found; 4709663SMark.Logan@Sun.COM } 4719663SMark.Logan@Sun.COM } else { 4729663SMark.Logan@Sun.COM oidpp++; 4739663SMark.Logan@Sun.COM } 4749663SMark.Logan@Sun.COM } 4759663SMark.Logan@Sun.COM return EJUSTRETURN; 4769663SMark.Logan@Sun.COMfound: 4779663SMark.Logan@Sun.COM 4789663SMark.Logan@Sun.COM /* If writing isn't allowed */ 4799663SMark.Logan@Sun.COM if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR)) 4809663SMark.Logan@Sun.COM return (EPERM); 4819663SMark.Logan@Sun.COM 4829663SMark.Logan@Sun.COM if (!(*oidpp)->oid_handler) 4839663SMark.Logan@Sun.COM return EINVAL; 4849663SMark.Logan@Sun.COM 4859663SMark.Logan@Sun.COM if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 4869663SMark.Logan@Sun.COM i = ((*oidpp)->oid_handler) (*oidpp, 4879663SMark.Logan@Sun.COM name + indx, namelen - indx, 4889663SMark.Logan@Sun.COM req); 4899663SMark.Logan@Sun.COM } else { 4909663SMark.Logan@Sun.COM i = ((*oidpp)->oid_handler) (*oidpp, 4919663SMark.Logan@Sun.COM (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 4929663SMark.Logan@Sun.COM req); 4939663SMark.Logan@Sun.COM } 4949663SMark.Logan@Sun.COM return (i); 4959663SMark.Logan@Sun.COM} 4969663SMark.Logan@Sun.COM 4979663SMark.Logan@Sun.COM#ifndef _SYS_SYSPROTO_H_ 4989663SMark.Logan@Sun.COMstruct sysctl_args { 4999663SMark.Logan@Sun.COM int *name; 5009663SMark.Logan@Sun.COM u_int namelen; 5019663SMark.Logan@Sun.COM void *old; 5029663SMark.Logan@Sun.COM size_t *oldlenp; 5039663SMark.Logan@Sun.COM void *new; 5049663SMark.Logan@Sun.COM size_t newlen; 5059663SMark.Logan@Sun.COM}; 5069663SMark.Logan@Sun.COM#endif 5079663SMark.Logan@Sun.COM 5089663SMark.Logan@Sun.COMint 5099663SMark.Logan@Sun.COM__sysctl(p, uap, retval) 5109663SMark.Logan@Sun.COM struct proc *p; 5119663SMark.Logan@Sun.COM register struct sysctl_args *uap; 5129663SMark.Logan@Sun.COM int *retval; 5139663SMark.Logan@Sun.COM{ 5149663SMark.Logan@Sun.COM int error, name[CTL_MAXNAME]; 5159663SMark.Logan@Sun.COM 5169663SMark.Logan@Sun.COM if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 5179663SMark.Logan@Sun.COM return (EINVAL); 5189663SMark.Logan@Sun.COM 5199663SMark.Logan@Sun.COM error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 5209663SMark.Logan@Sun.COM if (error) 5219663SMark.Logan@Sun.COM return (error); 5229663SMark.Logan@Sun.COM 5239663SMark.Logan@Sun.COM return (userland_sysctl(p, name, uap->namelen, 5249663SMark.Logan@Sun.COM uap->old, uap->oldlenp, 0, 5259663SMark.Logan@Sun.COM uap->new, uap->newlen, retval)); 5269663SMark.Logan@Sun.COM} 5279663SMark.Logan@Sun.COM 5289663SMark.Logan@Sun.COMstatic sysctlfn kern_sysctl; 5299663SMark.Logan@Sun.COM 5309663SMark.Logan@Sun.COM/* 5319663SMark.Logan@Sun.COM * This is used from various compatibility syscalls too. That's why name 5329663SMark.Logan@Sun.COM * must be in kernel space. 5339663SMark.Logan@Sun.COM */ 5349663SMark.Logan@Sun.COMint 5359663SMark.Logan@Sun.COMuserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval) 5369663SMark.Logan@Sun.COM{ 5379663SMark.Logan@Sun.COM int error = 0, dolock = 1, i, oldlen = 0; 5389663SMark.Logan@Sun.COM u_int savelen = 0; 5399663SMark.Logan@Sun.COM sysctlfn *fn; 5409663SMark.Logan@Sun.COM struct sysctl_req req; 5419663SMark.Logan@Sun.COM 5429663SMark.Logan@Sun.COM bzero(&req, sizeof req); 5439663SMark.Logan@Sun.COM 5449663SMark.Logan@Sun.COM if (new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 5459663SMark.Logan@Sun.COM return (error); 5469663SMark.Logan@Sun.COM 5479663SMark.Logan@Sun.COM if (oldlenp) { 5489663SMark.Logan@Sun.COM if (inkernel) { 5499663SMark.Logan@Sun.COM req.oldlen = *oldlenp; 5509663SMark.Logan@Sun.COM } else { 5519663SMark.Logan@Sun.COM error = copyin(oldlenp, &req.oldlen, 5529663SMark.Logan@Sun.COM sizeof(req.oldlen)); 5539663SMark.Logan@Sun.COM if (error) 5549663SMark.Logan@Sun.COM return (error); 5559663SMark.Logan@Sun.COM } 5569663SMark.Logan@Sun.COM oldlen = req.oldlen; 5579663SMark.Logan@Sun.COM } 5589663SMark.Logan@Sun.COM 5599663SMark.Logan@Sun.COM if (old) { 5609663SMark.Logan@Sun.COM if (!useracc(old, req.oldlen, B_WRITE)) 5619663SMark.Logan@Sun.COM return (EFAULT); 5629663SMark.Logan@Sun.COM req.oldptr= old; 5639663SMark.Logan@Sun.COM } 5649663SMark.Logan@Sun.COM 5659663SMark.Logan@Sun.COM if (newlen) { 5669663SMark.Logan@Sun.COM if (!useracc(new, req.newlen, B_READ)) 5679663SMark.Logan@Sun.COM return (EFAULT); 5689663SMark.Logan@Sun.COM req.newlen = newlen; 5699663SMark.Logan@Sun.COM req.newptr = new; 5709663SMark.Logan@Sun.COM } 5719663SMark.Logan@Sun.COM 5729663SMark.Logan@Sun.COM req.oldfunc = sysctl_old_user; 5739663SMark.Logan@Sun.COM req.newfunc = sysctl_new_user; 5749663SMark.Logan@Sun.COM 5759663SMark.Logan@Sun.COM error = sysctl_root(0, name, namelen, &req); 5769663SMark.Logan@Sun.COM 5779663SMark.Logan@Sun.COM if (!error || error == ENOMEM) { 5789663SMark.Logan@Sun.COM if (retval) 5799663SMark.Logan@Sun.COM *retval = req.oldlen; 5809663SMark.Logan@Sun.COM if (oldlenp) { 5819663SMark.Logan@Sun.COM if (inkernel) { 5829663SMark.Logan@Sun.COM *oldlenp = req.oldlen; 5839663SMark.Logan@Sun.COM } else { 5849663SMark.Logan@Sun.COM i = copyout(&req.oldlen, oldlenp, 5859663SMark.Logan@Sun.COM sizeof(req.oldlen)); 5869663SMark.Logan@Sun.COM if (i) 5879663SMark.Logan@Sun.COM error = i; 5889663SMark.Logan@Sun.COM } 5899663SMark.Logan@Sun.COM } 5909663SMark.Logan@Sun.COM return (error); 5919663SMark.Logan@Sun.COM } 5929663SMark.Logan@Sun.COM 5939663SMark.Logan@Sun.COM switch (name[0]) { 5949663SMark.Logan@Sun.COM case CTL_KERN: 5959663SMark.Logan@Sun.COM fn = kern_sysctl; 5969663SMark.Logan@Sun.COM if (name[1] != KERN_VNODE) /* XXX */ 5979663SMark.Logan@Sun.COM dolock = 0; 5989663SMark.Logan@Sun.COM break; 5999663SMark.Logan@Sun.COM case CTL_HW: 6009663SMark.Logan@Sun.COM fn = hw_sysctl; 6019663SMark.Logan@Sun.COM break; 6029663SMark.Logan@Sun.COM case CTL_VM: 6039663SMark.Logan@Sun.COM fn = vm_sysctl; 6049663SMark.Logan@Sun.COM break; 6059663SMark.Logan@Sun.COM case CTL_NET: 6069663SMark.Logan@Sun.COM fn = net_sysctl; 6079663SMark.Logan@Sun.COM break; 6089663SMark.Logan@Sun.COM case CTL_FS: 6099663SMark.Logan@Sun.COM fn = fs_sysctl; 6109663SMark.Logan@Sun.COM break; 6119663SMark.Logan@Sun.COM#ifdef DEBUG 6129663SMark.Logan@Sun.COM case CTL_DEBUG: 6139663SMark.Logan@Sun.COM fn = debug_sysctl; 6149663SMark.Logan@Sun.COM break; 6159663SMark.Logan@Sun.COM#endif 6169663SMark.Logan@Sun.COM default: 6179663SMark.Logan@Sun.COM return (EOPNOTSUPP); 6189663SMark.Logan@Sun.COM } 6199663SMark.Logan@Sun.COM if (old != NULL) { 6209663SMark.Logan@Sun.COM if (!useracc(old, oldlen, B_WRITE)) 6219663SMark.Logan@Sun.COM return (EFAULT); 6229663SMark.Logan@Sun.COM while (memlock.sl_lock) { 6239663SMark.Logan@Sun.COM memlock.sl_want = 1; 6249663SMark.Logan@Sun.COM (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 6259663SMark.Logan@Sun.COM memlock.sl_locked++; 6269663SMark.Logan@Sun.COM } 6279663SMark.Logan@Sun.COM memlock.sl_lock = 1; 6289663SMark.Logan@Sun.COM if (dolock) 6299663SMark.Logan@Sun.COM vslock(old, oldlen); 6309663SMark.Logan@Sun.COM savelen = oldlen; 6319663SMark.Logan@Sun.COM } 6329663SMark.Logan@Sun.COM 6339663SMark.Logan@Sun.COM 6349663SMark.Logan@Sun.COM error = (*fn)(name + 1, namelen - 1, old, &oldlen, 6359663SMark.Logan@Sun.COM new, newlen, p); 6369663SMark.Logan@Sun.COM 6379663SMark.Logan@Sun.COM 6389663SMark.Logan@Sun.COM if (old != NULL) { 6399663SMark.Logan@Sun.COM if (dolock) 6409663SMark.Logan@Sun.COM vsunlock(old, savelen, B_WRITE); 6419663SMark.Logan@Sun.COM memlock.sl_lock = 0; 6429663SMark.Logan@Sun.COM if (memlock.sl_want) { 6439663SMark.Logan@Sun.COM memlock.sl_want = 0; 6449663SMark.Logan@Sun.COM wakeup((caddr_t)&memlock); 6459663SMark.Logan@Sun.COM } 6469663SMark.Logan@Sun.COM } 6479663SMark.Logan@Sun.COM#if 0 6489663SMark.Logan@Sun.COM if (error) { 6499663SMark.Logan@Sun.COM printf("SYSCTL_ERROR: "); 6509663SMark.Logan@Sun.COM for(i=0;i<namelen;i++) 6519663SMark.Logan@Sun.COM printf("%d ", name[i]); 6529663SMark.Logan@Sun.COM printf("= %d\n", error); 6539663SMark.Logan@Sun.COM } 6549663SMark.Logan@Sun.COM#endif 6559663SMark.Logan@Sun.COM if (error) 6569663SMark.Logan@Sun.COM return (error); 6579663SMark.Logan@Sun.COM if (retval) 6589663SMark.Logan@Sun.COM *retval = oldlen; 6599663SMark.Logan@Sun.COM if (oldlenp) { 6609663SMark.Logan@Sun.COM if (inkernel) { 6619663SMark.Logan@Sun.COM *oldlenp = oldlen; 6629663SMark.Logan@Sun.COM } else { 6639663SMark.Logan@Sun.COM error = copyout(&oldlen, oldlenp, sizeof(oldlen)); 6649663SMark.Logan@Sun.COM } 6659663SMark.Logan@Sun.COM } 6669663SMark.Logan@Sun.COM return (error); 6679663SMark.Logan@Sun.COM} 6689663SMark.Logan@Sun.COM 6699663SMark.Logan@Sun.COM/* 6709663SMark.Logan@Sun.COM * Attributes stored in the kernel. 6719663SMark.Logan@Sun.COM */ 6729663SMark.Logan@Sun.COMint securelevel = -1; 6739663SMark.Logan@Sun.COM 6749663SMark.Logan@Sun.COM/* 6759663SMark.Logan@Sun.COM * kernel related system variables. 6769663SMark.Logan@Sun.COM */ 6779663SMark.Logan@Sun.COMstatic int 6789663SMark.Logan@Sun.COMkern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 6799663SMark.Logan@Sun.COM int *name; 6809663SMark.Logan@Sun.COM u_int namelen; 6819663SMark.Logan@Sun.COM void *oldp; 6829663SMark.Logan@Sun.COM size_t *oldlenp; 6839663SMark.Logan@Sun.COM void *newp; 6849663SMark.Logan@Sun.COM size_t newlen; 6859663SMark.Logan@Sun.COM struct proc *p; 6869663SMark.Logan@Sun.COM{ 6879663SMark.Logan@Sun.COM int error, level; 6889663SMark.Logan@Sun.COM dev_t ndumpdev; 6899663SMark.Logan@Sun.COM 6909663SMark.Logan@Sun.COM /* all sysctl names at this level are terminal */ 6919663SMark.Logan@Sun.COM if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF 6929663SMark.Logan@Sun.COM || name[0] == KERN_NTP_PLL)) 6939663SMark.Logan@Sun.COM return (ENOTDIR); /* overloaded */ 6949663SMark.Logan@Sun.COM 6959663SMark.Logan@Sun.COM switch (name[0]) { 6969663SMark.Logan@Sun.COM 6979663SMark.Logan@Sun.COM case KERN_SECURELVL: 6989663SMark.Logan@Sun.COM level = securelevel; 6999663SMark.Logan@Sun.COM if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 7009663SMark.Logan@Sun.COM newp == NULL) 7019663SMark.Logan@Sun.COM return (error); 7029663SMark.Logan@Sun.COM if (level < securelevel && p->p_pid != 1) 7039663SMark.Logan@Sun.COM return (EPERM); 7049663SMark.Logan@Sun.COM securelevel = level; 7059663SMark.Logan@Sun.COM return (0); 7069663SMark.Logan@Sun.COM case KERN_VNODE: 7079663SMark.Logan@Sun.COM return (sysctl_vnode(oldp, oldlenp)); 7089663SMark.Logan@Sun.COM case KERN_PROC: 7099663SMark.Logan@Sun.COM return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 7109663SMark.Logan@Sun.COM case KERN_FILE: 7119663SMark.Logan@Sun.COM return (sysctl_file(oldp, oldlenp)); 7129663SMark.Logan@Sun.COM#ifdef GPROF 7139663SMark.Logan@Sun.COM case KERN_PROF: 7149663SMark.Logan@Sun.COM return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 7159663SMark.Logan@Sun.COM newp, newlen)); 7169663SMark.Logan@Sun.COM#endif 7179663SMark.Logan@Sun.COM case KERN_NTP_PLL: 7189663SMark.Logan@Sun.COM return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp, 7199663SMark.Logan@Sun.COM newp, newlen, p)); 7209663SMark.Logan@Sun.COM case KERN_DUMPDEV: 7219663SMark.Logan@Sun.COM ndumpdev = dumpdev; 7229663SMark.Logan@Sun.COM error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev, 7239663SMark.Logan@Sun.COM sizeof ndumpdev); 7249663SMark.Logan@Sun.COM if (!error && ndumpdev != dumpdev) { 7259663SMark.Logan@Sun.COM error = setdumpdev(ndumpdev); 7269663SMark.Logan@Sun.COM } 7279663SMark.Logan@Sun.COM return error; 7289663SMark.Logan@Sun.COM default: 7299663SMark.Logan@Sun.COM return (EOPNOTSUPP); 7309663SMark.Logan@Sun.COM } 7319663SMark.Logan@Sun.COM /* NOTREACHED */ 7329663SMark.Logan@Sun.COM} 7339663SMark.Logan@Sun.COM 7349663SMark.Logan@Sun.COM/* 7359663SMark.Logan@Sun.COM * hardware related system variables. 7369663SMark.Logan@Sun.COM */ 7379663SMark.Logan@Sun.COMint 7389663SMark.Logan@Sun.COMhw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 7399663SMark.Logan@Sun.COM int *name; 7409663SMark.Logan@Sun.COM u_int namelen; 7419663SMark.Logan@Sun.COM void *oldp; 7429663SMark.Logan@Sun.COM size_t *oldlenp; 7439663SMark.Logan@Sun.COM void *newp; 7449663SMark.Logan@Sun.COM size_t newlen; 7459663SMark.Logan@Sun.COM struct proc *p; 7469663SMark.Logan@Sun.COM{ 7479663SMark.Logan@Sun.COM /* almost all sysctl names at this level are terminal */ 7489663SMark.Logan@Sun.COM if (namelen != 1 && name[0] != HW_DEVCONF) 7499663SMark.Logan@Sun.COM return (ENOTDIR); /* overloaded */ 7509663SMark.Logan@Sun.COM 7519663SMark.Logan@Sun.COM switch (name[0]) { 7529663SMark.Logan@Sun.COM case HW_PHYSMEM: 7539663SMark.Logan@Sun.COM return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 7549663SMark.Logan@Sun.COM case HW_USERMEM: 7559663SMark.Logan@Sun.COM return (sysctl_rdint(oldp, oldlenp, newp, 7569663SMark.Logan@Sun.COM ctob(physmem - cnt.v_wire_count))); 7579663SMark.Logan@Sun.COM case HW_DEVCONF: 7589663SMark.Logan@Sun.COM return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp, 7599663SMark.Logan@Sun.COM newp, newlen, p)); 7609663SMark.Logan@Sun.COM default: 7619663SMark.Logan@Sun.COM return (EOPNOTSUPP); 7629663SMark.Logan@Sun.COM } 7639663SMark.Logan@Sun.COM /* NOTREACHED */ 7649663SMark.Logan@Sun.COM} 7659663SMark.Logan@Sun.COM 7669663SMark.Logan@Sun.COM#ifdef DEBUG 7679663SMark.Logan@Sun.COM/* 7689663SMark.Logan@Sun.COM * Debugging related system variables. 7699663SMark.Logan@Sun.COM */ 7709663SMark.Logan@Sun.COMstruct ctldebug debug0, debug1, debug2, debug3, debug4; 7719663SMark.Logan@Sun.COMstruct ctldebug debug5, debug6, debug7, debug8, debug9; 7729663SMark.Logan@Sun.COMstruct ctldebug debug10, debug11, debug12, debug13, debug14; 7739663SMark.Logan@Sun.COMstruct ctldebug debug15, debug16, debug17, debug18, debug19; 7749663SMark.Logan@Sun.COMstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 7759663SMark.Logan@Sun.COM &debug0, &debug1, &debug2, &debug3, &debug4, 7769663SMark.Logan@Sun.COM &debug5, &debug6, &debug7, &debug8, &debug9, 7779663SMark.Logan@Sun.COM &debug10, &debug11, &debug12, &debug13, &debug14, 7789663SMark.Logan@Sun.COM &debug15, &debug16, &debug17, &debug18, &debug19, 7799663SMark.Logan@Sun.COM}; 7809663SMark.Logan@Sun.COMstatic int 7819663SMark.Logan@Sun.COMdebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 7829663SMark.Logan@Sun.COM int *name; 7839663SMark.Logan@Sun.COM u_int namelen; 7849663SMark.Logan@Sun.COM void *oldp; 7859663SMark.Logan@Sun.COM size_t *oldlenp; 7869663SMark.Logan@Sun.COM void *newp; 7879663SMark.Logan@Sun.COM size_t newlen; 7889663SMark.Logan@Sun.COM struct proc *p; 7899663SMark.Logan@Sun.COM{ 7909663SMark.Logan@Sun.COM struct ctldebug *cdp; 7919663SMark.Logan@Sun.COM 7929663SMark.Logan@Sun.COM /* all sysctl names at this level are name and field */ 7939663SMark.Logan@Sun.COM if (namelen != 2) 7949663SMark.Logan@Sun.COM return (ENOTDIR); /* overloaded */ 7959663SMark.Logan@Sun.COM cdp = debugvars[name[0]]; 7969663SMark.Logan@Sun.COM if (cdp->debugname == 0) 7979663SMark.Logan@Sun.COM return (EOPNOTSUPP); 7989663SMark.Logan@Sun.COM switch (name[1]) { 7999663SMark.Logan@Sun.COM case CTL_DEBUG_NAME: 8009663SMark.Logan@Sun.COM return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 8019663SMark.Logan@Sun.COM case CTL_DEBUG_VALUE: 8029663SMark.Logan@Sun.COM return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 8039663SMark.Logan@Sun.COM default: 8049663SMark.Logan@Sun.COM return (EOPNOTSUPP); 8059663SMark.Logan@Sun.COM } 8069663SMark.Logan@Sun.COM /* NOTREACHED */ 8079663SMark.Logan@Sun.COM} 8089663SMark.Logan@Sun.COM#endif /* DEBUG */ 8099663SMark.Logan@Sun.COM 8109663SMark.Logan@Sun.COM/* 8119663SMark.Logan@Sun.COM * Validate parameters and get old / set new parameters 8129663SMark.Logan@Sun.COM * for an integer-valued sysctl function. 8139663SMark.Logan@Sun.COM */ 8149663SMark.Logan@Sun.COMint 8159663SMark.Logan@Sun.COMsysctl_int(oldp, oldlenp, newp, newlen, valp) 8169663SMark.Logan@Sun.COM void *oldp; 8179663SMark.Logan@Sun.COM size_t *oldlenp; 8189663SMark.Logan@Sun.COM void *newp; 8199663SMark.Logan@Sun.COM size_t newlen; 8209663SMark.Logan@Sun.COM int *valp; 8219663SMark.Logan@Sun.COM{ 8229663SMark.Logan@Sun.COM int error = 0; 8239663SMark.Logan@Sun.COM 8249663SMark.Logan@Sun.COM if (oldp && *oldlenp < sizeof(int)) 8259663SMark.Logan@Sun.COM return (ENOMEM); 8269663SMark.Logan@Sun.COM if (newp && newlen != sizeof(int)) 8279663SMark.Logan@Sun.COM return (EINVAL); 8289663SMark.Logan@Sun.COM *oldlenp = sizeof(int); 8299663SMark.Logan@Sun.COM if (oldp) 8309663SMark.Logan@Sun.COM error = copyout(valp, oldp, sizeof(int)); 8319663SMark.Logan@Sun.COM if (error == 0 && newp) 8329663SMark.Logan@Sun.COM error = copyin(newp, valp, sizeof(int)); 8339663SMark.Logan@Sun.COM return (error); 8349663SMark.Logan@Sun.COM} 8359663SMark.Logan@Sun.COM 8369663SMark.Logan@Sun.COM/* 8379663SMark.Logan@Sun.COM * As above, but read-only. 8389663SMark.Logan@Sun.COM */ 8399663SMark.Logan@Sun.COMint 8409663SMark.Logan@Sun.COMsysctl_rdint(oldp, oldlenp, newp, val) 8419663SMark.Logan@Sun.COM void *oldp; 8429663SMark.Logan@Sun.COM size_t *oldlenp; 8439663SMark.Logan@Sun.COM void *newp; 8449663SMark.Logan@Sun.COM int val; 8459663SMark.Logan@Sun.COM{ 8469663SMark.Logan@Sun.COM int error = 0; 8479663SMark.Logan@Sun.COM 8489663SMark.Logan@Sun.COM if (oldp && *oldlenp < sizeof(int)) 8499663SMark.Logan@Sun.COM return (ENOMEM); 8509663SMark.Logan@Sun.COM if (newp) 8519663SMark.Logan@Sun.COM return (EPERM); 8529663SMark.Logan@Sun.COM *oldlenp = sizeof(int); 8539663SMark.Logan@Sun.COM if (oldp) 8549663SMark.Logan@Sun.COM error = copyout((caddr_t)&val, oldp, sizeof(int)); 8559663SMark.Logan@Sun.COM return (error); 8569663SMark.Logan@Sun.COM} 8579663SMark.Logan@Sun.COM 8589663SMark.Logan@Sun.COM/* 8599663SMark.Logan@Sun.COM * Validate parameters and get old / set new parameters 8609663SMark.Logan@Sun.COM * for a string-valued sysctl function. 8619663SMark.Logan@Sun.COM */ 8629663SMark.Logan@Sun.COMint 8639663SMark.Logan@Sun.COMsysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 8649663SMark.Logan@Sun.COM void *oldp; 8659663SMark.Logan@Sun.COM size_t *oldlenp; 8669663SMark.Logan@Sun.COM void *newp; 8679663SMark.Logan@Sun.COM size_t newlen; 8689663SMark.Logan@Sun.COM char *str; 8699663SMark.Logan@Sun.COM int maxlen; 8709663SMark.Logan@Sun.COM{ 8719663SMark.Logan@Sun.COM int len, error = 0, rval = 0; 8729663SMark.Logan@Sun.COM 8739663SMark.Logan@Sun.COM len = strlen(str) + 1; 8749663SMark.Logan@Sun.COM if (oldp && *oldlenp < len) { 8759663SMark.Logan@Sun.COM len = *oldlenp; 8769663SMark.Logan@Sun.COM rval = ENOMEM; 8779663SMark.Logan@Sun.COM } 8789663SMark.Logan@Sun.COM if (newp && newlen >= maxlen) 8799663SMark.Logan@Sun.COM return (EINVAL); 8809663SMark.Logan@Sun.COM if (oldp) { 8819663SMark.Logan@Sun.COM *oldlenp = len; 8829663SMark.Logan@Sun.COM error = copyout(str, oldp, len); 8839663SMark.Logan@Sun.COM if (error) 8849663SMark.Logan@Sun.COM rval = error; 8859663SMark.Logan@Sun.COM } 8869663SMark.Logan@Sun.COM if ((error == 0 || error == ENOMEM) && newp) { 8879663SMark.Logan@Sun.COM error = copyin(newp, str, newlen); 8889663SMark.Logan@Sun.COM if (error) 8899663SMark.Logan@Sun.COM rval = error; 8909663SMark.Logan@Sun.COM str[newlen] = 0; 8919663SMark.Logan@Sun.COM } 8929663SMark.Logan@Sun.COM return (rval); 8939663SMark.Logan@Sun.COM} 8949663SMark.Logan@Sun.COM 8959663SMark.Logan@Sun.COM/* 8969663SMark.Logan@Sun.COM * As above, but read-only. 8979663SMark.Logan@Sun.COM */ 8989663SMark.Logan@Sun.COMint 8999663SMark.Logan@Sun.COMsysctl_rdstring(oldp, oldlenp, newp, str) 9009663SMark.Logan@Sun.COM void *oldp; 9019663SMark.Logan@Sun.COM size_t *oldlenp; 9029663SMark.Logan@Sun.COM void *newp; 9039663SMark.Logan@Sun.COM char *str; 9049663SMark.Logan@Sun.COM{ 9059663SMark.Logan@Sun.COM int len, error = 0, rval = 0; 9069663SMark.Logan@Sun.COM 9079663SMark.Logan@Sun.COM len = strlen(str) + 1; 9089663SMark.Logan@Sun.COM if (oldp && *oldlenp < len) { 9099663SMark.Logan@Sun.COM len = *oldlenp; 9109663SMark.Logan@Sun.COM rval = ENOMEM; 9119663SMark.Logan@Sun.COM } 9129663SMark.Logan@Sun.COM if (newp) 9139663SMark.Logan@Sun.COM return (EPERM); 9149663SMark.Logan@Sun.COM *oldlenp = len; 9159663SMark.Logan@Sun.COM if (oldp) 9169663SMark.Logan@Sun.COM error = copyout(str, oldp, len); 9179663SMark.Logan@Sun.COM if (error) 9189663SMark.Logan@Sun.COM rval = error; 9199663SMark.Logan@Sun.COM return (rval); 9209663SMark.Logan@Sun.COM} 9219663SMark.Logan@Sun.COM 9229663SMark.Logan@Sun.COM/* 9239663SMark.Logan@Sun.COM * Validate parameters and get old / set new parameters 9249663SMark.Logan@Sun.COM * for a structure oriented sysctl function. 9259663SMark.Logan@Sun.COM */ 9269663SMark.Logan@Sun.COMint 9279663SMark.Logan@Sun.COMsysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 9289663SMark.Logan@Sun.COM void *oldp; 9299663SMark.Logan@Sun.COM size_t *oldlenp; 9309663SMark.Logan@Sun.COM void *newp; 9319663SMark.Logan@Sun.COM size_t newlen; 9329663SMark.Logan@Sun.COM void *sp; 9339663SMark.Logan@Sun.COM int len; 9349663SMark.Logan@Sun.COM{ 9359663SMark.Logan@Sun.COM int error = 0; 9369663SMark.Logan@Sun.COM 9379663SMark.Logan@Sun.COM if (oldp && *oldlenp < len) 9389663SMark.Logan@Sun.COM return (ENOMEM); 9399663SMark.Logan@Sun.COM if (newp && newlen > len) 9409663SMark.Logan@Sun.COM return (EINVAL); 9419663SMark.Logan@Sun.COM if (oldp) { 9429663SMark.Logan@Sun.COM *oldlenp = len; 9439663SMark.Logan@Sun.COM error = copyout(sp, oldp, len); 9449663SMark.Logan@Sun.COM } 9459663SMark.Logan@Sun.COM if (error == 0 && newp) 9469663SMark.Logan@Sun.COM error = copyin(newp, sp, len); 9479663SMark.Logan@Sun.COM return (error); 9489663SMark.Logan@Sun.COM} 9499663SMark.Logan@Sun.COM 9509663SMark.Logan@Sun.COM/* 9519663SMark.Logan@Sun.COM * Validate parameters and get old parameters 9529663SMark.Logan@Sun.COM * for a structure oriented sysctl function. 9539663SMark.Logan@Sun.COM */ 9549663SMark.Logan@Sun.COMint 9559663SMark.Logan@Sun.COMsysctl_rdstruct(oldp, oldlenp, newp, sp, len) 9569663SMark.Logan@Sun.COM void *oldp; 9579663SMark.Logan@Sun.COM size_t *oldlenp; 9589663SMark.Logan@Sun.COM void *newp, *sp; 9599663SMark.Logan@Sun.COM int len; 9609663SMark.Logan@Sun.COM{ 9619663SMark.Logan@Sun.COM int error = 0; 9629663SMark.Logan@Sun.COM 9639663SMark.Logan@Sun.COM if (oldp && *oldlenp < len) 9649663SMark.Logan@Sun.COM return (ENOMEM); 9659663SMark.Logan@Sun.COM if (newp) 9669663SMark.Logan@Sun.COM return (EPERM); 9679663SMark.Logan@Sun.COM *oldlenp = len; 9689663SMark.Logan@Sun.COM if (oldp) 9699663SMark.Logan@Sun.COM error = copyout(sp, oldp, len); 9709663SMark.Logan@Sun.COM return (error); 9719663SMark.Logan@Sun.COM} 9729663SMark.Logan@Sun.COM 9739663SMark.Logan@Sun.COM/* 9749663SMark.Logan@Sun.COM * Get file structures. 9759663SMark.Logan@Sun.COM */ 9769663SMark.Logan@Sun.COMint 9779663SMark.Logan@Sun.COMsysctl_file(where, sizep) 9789663SMark.Logan@Sun.COM char *where; 9799663SMark.Logan@Sun.COM size_t *sizep; 9809663SMark.Logan@Sun.COM{ 9819663SMark.Logan@Sun.COM int buflen, error; 9829663SMark.Logan@Sun.COM struct file *fp; 9839663SMark.Logan@Sun.COM char *start = where; 9849663SMark.Logan@Sun.COM 9859663SMark.Logan@Sun.COM buflen = *sizep; 9869663SMark.Logan@Sun.COM if (where == NULL) { 9879663SMark.Logan@Sun.COM /* 9889663SMark.Logan@Sun.COM * overestimate by 10 files 9899663SMark.Logan@Sun.COM */ 9909663SMark.Logan@Sun.COM *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 9919663SMark.Logan@Sun.COM return (0); 9929663SMark.Logan@Sun.COM } 9939663SMark.Logan@Sun.COM 9949663SMark.Logan@Sun.COM /* 9959663SMark.Logan@Sun.COM * first copyout filehead 9969663SMark.Logan@Sun.COM */ 9979663SMark.Logan@Sun.COM if (buflen < sizeof(filehead)) { 9989663SMark.Logan@Sun.COM *sizep = 0; 9999663SMark.Logan@Sun.COM return (0); 10009663SMark.Logan@Sun.COM } 10019663SMark.Logan@Sun.COM error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 10029663SMark.Logan@Sun.COM if (error) 10039663SMark.Logan@Sun.COM return (error); 10049663SMark.Logan@Sun.COM buflen -= sizeof(filehead); 10059663SMark.Logan@Sun.COM where += sizeof(filehead); 10069663SMark.Logan@Sun.COM 10079663SMark.Logan@Sun.COM /* 10089663SMark.Logan@Sun.COM * followed by an array of file structures 10099663SMark.Logan@Sun.COM */ 10109663SMark.Logan@Sun.COM for (fp = filehead; fp != NULL; fp = fp->f_filef) { 10119663SMark.Logan@Sun.COM if (buflen < sizeof(struct file)) { 10129663SMark.Logan@Sun.COM *sizep = where - start; 10139663SMark.Logan@Sun.COM return (ENOMEM); 10149663SMark.Logan@Sun.COM } 10159663SMark.Logan@Sun.COM error = copyout((caddr_t)fp, where, sizeof (struct file)); 10169663SMark.Logan@Sun.COM if (error) 10179663SMark.Logan@Sun.COM return (error); 10189663SMark.Logan@Sun.COM buflen -= sizeof(struct file); 10199663SMark.Logan@Sun.COM where += sizeof(struct file); 10209663SMark.Logan@Sun.COM } 10219663SMark.Logan@Sun.COM *sizep = where - start; 10229663SMark.Logan@Sun.COM return (0); 10239663SMark.Logan@Sun.COM} 10249663SMark.Logan@Sun.COM 10259663SMark.Logan@Sun.COM/* 10269663SMark.Logan@Sun.COM * try over estimating by 5 procs 10279663SMark.Logan@Sun.COM */ 10289663SMark.Logan@Sun.COM#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 10299663SMark.Logan@Sun.COM 10309663SMark.Logan@Sun.COMint 10319663SMark.Logan@Sun.COMsysctl_doproc(name, namelen, where, sizep) 10329663SMark.Logan@Sun.COM int *name; 10339663SMark.Logan@Sun.COM u_int namelen; 10349663SMark.Logan@Sun.COM char *where; 10359663SMark.Logan@Sun.COM size_t *sizep; 10369663SMark.Logan@Sun.COM{ 10379663SMark.Logan@Sun.COM register struct proc *p; 10389663SMark.Logan@Sun.COM register struct kinfo_proc *dp = (struct kinfo_proc *)where; 10399663SMark.Logan@Sun.COM register int needed = 0; 10409663SMark.Logan@Sun.COM int buflen = where != NULL ? *sizep : 0; 10419663SMark.Logan@Sun.COM int doingzomb; 10429663SMark.Logan@Sun.COM struct eproc eproc; 10439663SMark.Logan@Sun.COM int error = 0; 10449663SMark.Logan@Sun.COM 10459663SMark.Logan@Sun.COM if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 10469663SMark.Logan@Sun.COM return (EINVAL); 10479663SMark.Logan@Sun.COM p = (struct proc *)allproc; 10489663SMark.Logan@Sun.COM doingzomb = 0; 10499663SMark.Logan@Sun.COMagain: 10509663SMark.Logan@Sun.COM for (; p != NULL; p = p->p_next) { 10519663SMark.Logan@Sun.COM /* 10529663SMark.Logan@Sun.COM * Skip embryonic processes. 10539663SMark.Logan@Sun.COM */ 10549663SMark.Logan@Sun.COM if (p->p_stat == SIDL) 10559663SMark.Logan@Sun.COM continue; 10569663SMark.Logan@Sun.COM /* 10579663SMark.Logan@Sun.COM * TODO - make more efficient (see notes below). 10589663SMark.Logan@Sun.COM * do by session. 10599663SMark.Logan@Sun.COM */ 10609663SMark.Logan@Sun.COM switch (name[0]) { 10619663SMark.Logan@Sun.COM 10629663SMark.Logan@Sun.COM case KERN_PROC_PID: 10639663SMark.Logan@Sun.COM /* could do this with just a lookup */ 10649663SMark.Logan@Sun.COM if (p->p_pid != (pid_t)name[1]) 10659663SMark.Logan@Sun.COM continue; 10669663SMark.Logan@Sun.COM break; 10679663SMark.Logan@Sun.COM 10689663SMark.Logan@Sun.COM case KERN_PROC_PGRP: 10699663SMark.Logan@Sun.COM /* could do this by traversing pgrp */ 10709663SMark.Logan@Sun.COM if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1]) 10719663SMark.Logan@Sun.COM continue; 10729663SMark.Logan@Sun.COM break; 10739663SMark.Logan@Sun.COM 10749663SMark.Logan@Sun.COM case KERN_PROC_TTY: 10759663SMark.Logan@Sun.COM if ((p->p_flag & P_CONTROLT) == 0 || 10769663SMark.Logan@Sun.COM p->p_session == NULL || 10779663SMark.Logan@Sun.COM p->p_session->s_ttyp == NULL || 10789663SMark.Logan@Sun.COM p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 10799663SMark.Logan@Sun.COM continue; 10809663SMark.Logan@Sun.COM break; 10819663SMark.Logan@Sun.COM 10829663SMark.Logan@Sun.COM case KERN_PROC_UID: 10839663SMark.Logan@Sun.COM if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1]) 10849663SMark.Logan@Sun.COM continue; 10859663SMark.Logan@Sun.COM break; 10869663SMark.Logan@Sun.COM 10879663SMark.Logan@Sun.COM case KERN_PROC_RUID: 10889663SMark.Logan@Sun.COM if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1]) 10899663SMark.Logan@Sun.COM continue; 10909663SMark.Logan@Sun.COM break; 10919663SMark.Logan@Sun.COM } 10929663SMark.Logan@Sun.COM if (buflen >= sizeof(struct kinfo_proc)) { 10939663SMark.Logan@Sun.COM fill_eproc(p, &eproc); 10949663SMark.Logan@Sun.COM error = copyout((caddr_t)p, &dp->kp_proc, 10959663SMark.Logan@Sun.COM sizeof(struct proc)); 10969663SMark.Logan@Sun.COM if (error) 10979663SMark.Logan@Sun.COM return (error); 10989663SMark.Logan@Sun.COM error = copyout((caddr_t)&eproc, &dp->kp_eproc, 10999663SMark.Logan@Sun.COM sizeof(eproc)); 11009663SMark.Logan@Sun.COM if (error) 11019663SMark.Logan@Sun.COM return (error); 11029663SMark.Logan@Sun.COM dp++; 11039663SMark.Logan@Sun.COM buflen -= sizeof(struct kinfo_proc); 11049663SMark.Logan@Sun.COM } 11059663SMark.Logan@Sun.COM needed += sizeof(struct kinfo_proc); 11069663SMark.Logan@Sun.COM } 11079663SMark.Logan@Sun.COM if (doingzomb == 0) { 11089663SMark.Logan@Sun.COM p = zombproc; 11099663SMark.Logan@Sun.COM doingzomb++; 11109663SMark.Logan@Sun.COM goto again; 11119663SMark.Logan@Sun.COM } 11129663SMark.Logan@Sun.COM if (where != NULL) { 11139663SMark.Logan@Sun.COM *sizep = (caddr_t)dp - where; 11149663SMark.Logan@Sun.COM if (needed > *sizep) 11159663SMark.Logan@Sun.COM return (ENOMEM); 11169663SMark.Logan@Sun.COM } else { 11179663SMark.Logan@Sun.COM needed += KERN_PROCSLOP; 11189663SMark.Logan@Sun.COM *sizep = needed; 11199663SMark.Logan@Sun.COM } 11209663SMark.Logan@Sun.COM return (0); 11219663SMark.Logan@Sun.COM} 11229663SMark.Logan@Sun.COM 11239663SMark.Logan@Sun.COM/* 11249663SMark.Logan@Sun.COM * Fill in an eproc structure for the specified process. 11259663SMark.Logan@Sun.COM */ 11269663SMark.Logan@Sun.COMvoid 11279663SMark.Logan@Sun.COMfill_eproc(p, ep) 11289663SMark.Logan@Sun.COM register struct proc *p; 11299663SMark.Logan@Sun.COM register struct eproc *ep; 11309663SMark.Logan@Sun.COM{ 11319663SMark.Logan@Sun.COM register struct tty *tp; 11329663SMark.Logan@Sun.COM 11339663SMark.Logan@Sun.COM bzero(ep, sizeof(*ep)); 11349663SMark.Logan@Sun.COM 11359663SMark.Logan@Sun.COM ep->e_paddr = p; 11369663SMark.Logan@Sun.COM if (p->p_cred) { 11379663SMark.Logan@Sun.COM ep->e_pcred = *p->p_cred; 11389663SMark.Logan@Sun.COM if (p->p_ucred) 11399663SMark.Logan@Sun.COM ep->e_ucred = *p->p_ucred; 11409663SMark.Logan@Sun.COM } 11419663SMark.Logan@Sun.COM if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) { 11429663SMark.Logan@Sun.COM register struct vmspace *vm = p->p_vmspace; 11439663SMark.Logan@Sun.COM 11449663SMark.Logan@Sun.COM#ifdef pmap_resident_count 11459663SMark.Logan@Sun.COM ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/ 11469663SMark.Logan@Sun.COM#else 11479663SMark.Logan@Sun.COM ep->e_vm.vm_rssize = vm->vm_rssize; 11489663SMark.Logan@Sun.COM#endif 11499663SMark.Logan@Sun.COM ep->e_vm.vm_tsize = vm->vm_tsize; 11509663SMark.Logan@Sun.COM ep->e_vm.vm_dsize = vm->vm_dsize; 11519663SMark.Logan@Sun.COM ep->e_vm.vm_ssize = vm->vm_ssize; 11529663SMark.Logan@Sun.COM#ifndef sparc 11539663SMark.Logan@Sun.COM ep->e_vm.vm_pmap = vm->vm_pmap; 11549663SMark.Logan@Sun.COM#endif 11559663SMark.Logan@Sun.COM } 11569663SMark.Logan@Sun.COM if (p->p_pptr) 11579663SMark.Logan@Sun.COM ep->e_ppid = p->p_pptr->p_pid; 11589663SMark.Logan@Sun.COM if (p->p_pgrp) { 11599663SMark.Logan@Sun.COM ep->e_sess = p->p_pgrp->pg_session; 11609663SMark.Logan@Sun.COM ep->e_pgid = p->p_pgrp->pg_id; 11619663SMark.Logan@Sun.COM ep->e_jobc = p->p_pgrp->pg_jobc; 11629663SMark.Logan@Sun.COM } 11639663SMark.Logan@Sun.COM if ((p->p_flag & P_CONTROLT) && 11649663SMark.Logan@Sun.COM (ep->e_sess != NULL) && 11659663SMark.Logan@Sun.COM ((tp = ep->e_sess->s_ttyp) != NULL)) { 11669663SMark.Logan@Sun.COM ep->e_tdev = tp->t_dev; 11679663SMark.Logan@Sun.COM ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 11689663SMark.Logan@Sun.COM ep->e_tsess = tp->t_session; 11699663SMark.Logan@Sun.COM } else 11709663SMark.Logan@Sun.COM ep->e_tdev = NODEV; 11719663SMark.Logan@Sun.COM if (ep->e_sess && ep->e_sess->s_ttyvp) 11729663SMark.Logan@Sun.COM ep->e_flag = EPROC_CTTY; 11739663SMark.Logan@Sun.COM if (SESS_LEADER(p)) 11749663SMark.Logan@Sun.COM ep->e_flag |= EPROC_SLEADER; 11759663SMark.Logan@Sun.COM if (p->p_wmesg) { 11769663SMark.Logan@Sun.COM strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 11779663SMark.Logan@Sun.COM ep->e_wmesg[WMESGLEN] = 0; 11789663SMark.Logan@Sun.COM } 11799663SMark.Logan@Sun.COM} 11809663SMark.Logan@Sun.COM 11819663SMark.Logan@Sun.COM#ifdef COMPAT_43 11829663SMark.Logan@Sun.COM#include <sys/socket.h> 11839663SMark.Logan@Sun.COM#define KINFO_PROC (0<<8) 11849663SMark.Logan@Sun.COM#define KINFO_RT (1<<8) 11859663SMark.Logan@Sun.COM#define KINFO_VNODE (2<<8) 11869663SMark.Logan@Sun.COM#define KINFO_FILE (3<<8) 11879663SMark.Logan@Sun.COM#define KINFO_METER (4<<8) 11889663SMark.Logan@Sun.COM#define KINFO_LOADAVG (5<<8) 11899663SMark.Logan@Sun.COM#define KINFO_CLOCKRATE (6<<8) 11909663SMark.Logan@Sun.COM 11919663SMark.Logan@Sun.COM/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 11929663SMark.Logan@Sun.COM#define KINFO_BSDI_SYSINFO (101<<8) 11939663SMark.Logan@Sun.COM 11949663SMark.Logan@Sun.COM/* 11959663SMark.Logan@Sun.COM * XXX this is bloat, but I hope it's better here than on the potentially 11969663SMark.Logan@Sun.COM * limited kernel stack... -Peter 11979663SMark.Logan@Sun.COM */ 11989663SMark.Logan@Sun.COM 11999663SMark.Logan@Sun.COMstruct { 12009663SMark.Logan@Sun.COM int bsdi_machine; /* "i386" on BSD/386 */ 12019663SMark.Logan@Sun.COM/* ^^^ this is an offset to the string, relative to the struct start */ 12029663SMark.Logan@Sun.COM char *pad0; 12039663SMark.Logan@Sun.COM long pad1; 12049663SMark.Logan@Sun.COM long pad2; 12059663SMark.Logan@Sun.COM long pad3; 12069663SMark.Logan@Sun.COM u_long pad4; 12079663SMark.Logan@Sun.COM u_long pad5; 12089663SMark.Logan@Sun.COM u_long pad6; 12099663SMark.Logan@Sun.COM 12109663SMark.Logan@Sun.COM int bsdi_ostype; /* "BSD/386" on BSD/386 */ 12119663SMark.Logan@Sun.COM int bsdi_osrelease; /* "1.1" on BSD/386 */ 12129663SMark.Logan@Sun.COM long pad7; 12139663SMark.Logan@Sun.COM long pad8; 12149663SMark.Logan@Sun.COM char *pad9; 12159663SMark.Logan@Sun.COM 12169663SMark.Logan@Sun.COM long pad10; 12179663SMark.Logan@Sun.COM long pad11; 12189663SMark.Logan@Sun.COM int pad12; 12199663SMark.Logan@Sun.COM long pad13; 12209663SMark.Logan@Sun.COM quad_t pad14; 12219663SMark.Logan@Sun.COM long pad15; 12229663SMark.Logan@Sun.COM 12239663SMark.Logan@Sun.COM struct timeval pad16; 12249663SMark.Logan@Sun.COM /* we dont set this, because BSDI's uname used gethostname() instead */ 12259663SMark.Logan@Sun.COM int bsdi_hostname; /* hostname on BSD/386 */ 12269663SMark.Logan@Sun.COM 12279663SMark.Logan@Sun.COM /* the actual string data is appended here */ 12289663SMark.Logan@Sun.COM 12299663SMark.Logan@Sun.COM} bsdi_si; 12309663SMark.Logan@Sun.COM/* 12319663SMark.Logan@Sun.COM * this data is appended to the end of the bsdi_si structure during copyout. 12329663SMark.Logan@Sun.COM * The "char *" offsets are relative to the base of the bsdi_si struct. 12339663SMark.Logan@Sun.COM * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 12349663SMark.Logan@Sun.COM * should not exceed the length of the buffer here... (or else!! :-) 12359663SMark.Logan@Sun.COM */ 12369663SMark.Logan@Sun.COMchar bsdi_strings[80]; /* It had better be less than this! */ 12379663SMark.Logan@Sun.COM 12389663SMark.Logan@Sun.COM#ifndef _SYS_SYSPROTO_H_ 12399663SMark.Logan@Sun.COMstruct getkerninfo_args { 12409663SMark.Logan@Sun.COM int op; 12419663SMark.Logan@Sun.COM char *where; 12429663SMark.Logan@Sun.COM int *size; 12439663SMark.Logan@Sun.COM int arg; 12449663SMark.Logan@Sun.COM}; 12459663SMark.Logan@Sun.COM#endif 12469663SMark.Logan@Sun.COM 12479663SMark.Logan@Sun.COMint 12489663SMark.Logan@Sun.COMogetkerninfo(p, uap, retval) 12499663SMark.Logan@Sun.COM struct proc *p; 12509663SMark.Logan@Sun.COM register struct getkerninfo_args *uap; 12519663SMark.Logan@Sun.COM int *retval; 12529663SMark.Logan@Sun.COM{ 12539663SMark.Logan@Sun.COM int error, name[6]; 12549663SMark.Logan@Sun.COM u_int size; 12559663SMark.Logan@Sun.COM 12569663SMark.Logan@Sun.COM switch (uap->op & 0xff00) { 12579663SMark.Logan@Sun.COM 12589663SMark.Logan@Sun.COM case KINFO_RT: 12599663SMark.Logan@Sun.COM name[0] = CTL_NET; 12609663SMark.Logan@Sun.COM name[1] = PF_ROUTE; 12619663SMark.Logan@Sun.COM name[2] = 0; 12629663SMark.Logan@Sun.COM name[3] = (uap->op & 0xff0000) >> 16; 12639663SMark.Logan@Sun.COM name[4] = uap->op & 0xff; 12649663SMark.Logan@Sun.COM name[5] = uap->arg; 12659663SMark.Logan@Sun.COM error = userland_sysctl(p, name, 6, uap->where, uap->size, 12669663SMark.Logan@Sun.COM 0, 0, 0, 0); 12679663SMark.Logan@Sun.COM break; 12689663SMark.Logan@Sun.COM 12699663SMark.Logan@Sun.COM case KINFO_VNODE: 12709663SMark.Logan@Sun.COM name[0] = CTL_KERN; 12719663SMark.Logan@Sun.COM name[1] = KERN_VNODE; 12729663SMark.Logan@Sun.COM error = userland_sysctl(p, name, 2, uap->where, uap->size, 12739663SMark.Logan@Sun.COM 0, 0, 0, 0); 12749663SMark.Logan@Sun.COM break; 12759663SMark.Logan@Sun.COM 12769663SMark.Logan@Sun.COM case KINFO_PROC: 12779663SMark.Logan@Sun.COM name[0] = CTL_KERN; 12789663SMark.Logan@Sun.COM name[1] = KERN_PROC; 12799663SMark.Logan@Sun.COM name[2] = uap->op & 0xff; 12809663SMark.Logan@Sun.COM name[3] = uap->arg; 12819663SMark.Logan@Sun.COM error = userland_sysctl(p, name, 4, uap->where, uap->size, 12829663SMark.Logan@Sun.COM 0, 0, 0, 0); 12839663SMark.Logan@Sun.COM break; 12849663SMark.Logan@Sun.COM 12859663SMark.Logan@Sun.COM case KINFO_FILE: 12869663SMark.Logan@Sun.COM name[0] = CTL_KERN; 12879663SMark.Logan@Sun.COM name[1] = KERN_FILE; 12889663SMark.Logan@Sun.COM error = userland_sysctl(p, name, 2, uap->where, uap->size, 12899663SMark.Logan@Sun.COM 0, 0, 0, 0); 12909663SMark.Logan@Sun.COM break; 12919663SMark.Logan@Sun.COM 12929663SMark.Logan@Sun.COM case KINFO_METER: 12939663SMark.Logan@Sun.COM name[0] = CTL_VM; 12949663SMark.Logan@Sun.COM name[1] = VM_METER; 12959663SMark.Logan@Sun.COM error = userland_sysctl(p, name, 2, uap->where, uap->size, 12969663SMark.Logan@Sun.COM 0, 0, 0, 0); 12979663SMark.Logan@Sun.COM break; 12989663SMark.Logan@Sun.COM 12999663SMark.Logan@Sun.COM case KINFO_LOADAVG: 13009663SMark.Logan@Sun.COM name[0] = CTL_VM; 13019663SMark.Logan@Sun.COM name[1] = VM_LOADAVG; 13029663SMark.Logan@Sun.COM error = userland_sysctl(p, name, 2, uap->where, uap->size, 13039663SMark.Logan@Sun.COM 0, 0, 0, 0); 13049663SMark.Logan@Sun.COM break; 13059663SMark.Logan@Sun.COM 13069663SMark.Logan@Sun.COM case KINFO_CLOCKRATE: 13079663SMark.Logan@Sun.COM name[0] = CTL_KERN; 13089663SMark.Logan@Sun.COM name[1] = KERN_CLOCKRATE; 13099663SMark.Logan@Sun.COM error = userland_sysctl(p, name, 2, uap->where, uap->size, 13109663SMark.Logan@Sun.COM 0, 0, 0, 0); 13119663SMark.Logan@Sun.COM break; 13129663SMark.Logan@Sun.COM 13139663SMark.Logan@Sun.COM case KINFO_BSDI_SYSINFO: { 13149663SMark.Logan@Sun.COM /* 13159663SMark.Logan@Sun.COM * this is pretty crude, but it's just enough for uname() 13169663SMark.Logan@Sun.COM * from BSDI's 1.x libc to work. 13179663SMark.Logan@Sun.COM * 13189663SMark.Logan@Sun.COM * In particular, it doesn't return the same results when 13199663SMark.Logan@Sun.COM * the supplied buffer is too small. BSDI's version apparently 13209663SMark.Logan@Sun.COM * will return the amount copied, and set the *size to how 13219663SMark.Logan@Sun.COM * much was needed. The emulation framework here isn't capable 13229663SMark.Logan@Sun.COM * of that, so we just set both to the amount copied. 13239663SMark.Logan@Sun.COM * BSDI's 2.x product apparently fails with ENOMEM in this 13249663SMark.Logan@Sun.COM * scenario. 13259663SMark.Logan@Sun.COM */ 13269663SMark.Logan@Sun.COM 13279663SMark.Logan@Sun.COM u_int needed; 13289663SMark.Logan@Sun.COM u_int left; 13299663SMark.Logan@Sun.COM char *s; 13309663SMark.Logan@Sun.COM 13319663SMark.Logan@Sun.COM bzero((char *)&bsdi_si, sizeof(bsdi_si)); 13329663SMark.Logan@Sun.COM bzero(bsdi_strings, sizeof(bsdi_strings)); 13339663SMark.Logan@Sun.COM 13349663SMark.Logan@Sun.COM s = bsdi_strings; 13359663SMark.Logan@Sun.COM 13369663SMark.Logan@Sun.COM bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 13379663SMark.Logan@Sun.COM strcpy(s, ostype); 13389663SMark.Logan@Sun.COM s += strlen(s) + 1; 13399663SMark.Logan@Sun.COM 13409663SMark.Logan@Sun.COM bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 13419663SMark.Logan@Sun.COM strcpy(s, osrelease); 13429663SMark.Logan@Sun.COM s += strlen(s) + 1; 13439663SMark.Logan@Sun.COM 13449663SMark.Logan@Sun.COM bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 13459663SMark.Logan@Sun.COM strcpy(s, machine); 13469663SMark.Logan@Sun.COM s += strlen(s) + 1; 13479663SMark.Logan@Sun.COM 13489663SMark.Logan@Sun.COM needed = sizeof(bsdi_si) + (s - bsdi_strings); 13499663SMark.Logan@Sun.COM 13509663SMark.Logan@Sun.COM if (uap->where == NULL) { 13519663SMark.Logan@Sun.COM /* process is asking how much buffer to supply.. */ 13529663SMark.Logan@Sun.COM size = needed; 13539663SMark.Logan@Sun.COM error = 0; 13549663SMark.Logan@Sun.COM break; 13559663SMark.Logan@Sun.COM } 13569663SMark.Logan@Sun.COM 13579663SMark.Logan@Sun.COM 13589663SMark.Logan@Sun.COM /* if too much buffer supplied, trim it down */ 13599663SMark.Logan@Sun.COM if (size > needed) 13609663SMark.Logan@Sun.COM size = needed; 13619663SMark.Logan@Sun.COM 13629663SMark.Logan@Sun.COM /* how much of the buffer is remaining */ 13639663SMark.Logan@Sun.COM left = size; 13649663SMark.Logan@Sun.COM 13659663SMark.Logan@Sun.COM if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 13669663SMark.Logan@Sun.COM break; 13679663SMark.Logan@Sun.COM 13689663SMark.Logan@Sun.COM /* is there any point in continuing? */ 13699663SMark.Logan@Sun.COM if (left > sizeof(bsdi_si)) { 13709663SMark.Logan@Sun.COM left -= sizeof(bsdi_si); 13719663SMark.Logan@Sun.COM error = copyout(&bsdi_strings, 13729663SMark.Logan@Sun.COM uap->where + sizeof(bsdi_si), left); 13739663SMark.Logan@Sun.COM } 13749663SMark.Logan@Sun.COM break; 13759663SMark.Logan@Sun.COM } 13769663SMark.Logan@Sun.COM 13779663SMark.Logan@Sun.COM default: 13789663SMark.Logan@Sun.COM return (EOPNOTSUPP); 13799663SMark.Logan@Sun.COM } 13809663SMark.Logan@Sun.COM if (error) 13819663SMark.Logan@Sun.COM return (error); 13829663SMark.Logan@Sun.COM *retval = size; 13839663SMark.Logan@Sun.COM if (uap->size) 13849663SMark.Logan@Sun.COM error = copyout((caddr_t)&size, (caddr_t)uap->size, 13859663SMark.Logan@Sun.COM sizeof(size)); 13869663SMark.Logan@Sun.COM return (error); 13879663SMark.Logan@Sun.COM} 13889663SMark.Logan@Sun.COM#endif /* COMPAT_43 */ 13899663SMark.Logan@Sun.COM