kern_sysctl.c revision 12197
1184610Salfred/*- 2184610Salfred * Copyright (c) 1982, 1986, 1989, 1993 3184610Salfred * The Regents of the University of California. All rights reserved. 4184610Salfred * 5184610Salfred * This code is derived from software contributed to Berkeley by 6184610Salfred * Mike Karels at Berkeley Software Design, Inc. 7184610Salfred * 8184610Salfred * Redistribution and use in source and binary forms, with or without 9184610Salfred * modification, are permitted provided that the following conditions 10184610Salfred * are met: 11184610Salfred * 1. Redistributions of source code must retain the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer. 13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer in the 15184610Salfred * documentation and/or other materials provided with the distribution. 16184610Salfred * 3. All advertising materials mentioning features or use of this software 17184610Salfred * must display the following acknowledgement: 18184610Salfred * This product includes software developed by the University of 19184610Salfred * California, Berkeley and its contributors. 20184610Salfred * 4. Neither the name of the University nor the names of its contributors 21184610Salfred * may be used to endorse or promote products derived from this software 22184610Salfred * without specific prior written permission. 23184610Salfred * 24184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27194677Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28194677Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29194677Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30194677Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31194677Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32194677Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33194677Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34194677Sthompsa * SUCH DAMAGE. 35194677Sthompsa * 36194677Sthompsa * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 37194677Sthompsa * $Id: kern_sysctl.c,v 1.35 1995/11/10 16:22:41 phk Exp $ 38194677Sthompsa */ 39194677Sthompsa 40194677Sthompsa/* 41194677Sthompsa * sysctl system call. 42194677Sthompsa */ 43194677Sthompsa 44194677Sthompsa#include <sys/param.h> 45194677Sthompsa#include <sys/systm.h> 46194677Sthompsa#include <sys/kernel.h> 47194677Sthompsa#include <sys/malloc.h> 48194677Sthompsa#include <sys/proc.h> 49188942Sthompsa#include <sys/file.h> 50188942Sthompsa#include <sys/vnode.h> 51194677Sthompsa#include <sys/unistd.h> 52194677Sthompsa#include <sys/buf.h> 53184610Salfred#include <sys/ioctl.h> 54184610Salfred#include <sys/tty.h> 55184610Salfred#include <sys/conf.h> 56188942Sthompsa#include <vm/vm.h> 57194677Sthompsa#include <sys/sysctl.h> 58188942Sthompsa#include <sys/user.h> 59188942Sthompsa 60188942Sthompsaextern struct linker_set sysctl_; 61188942Sthompsa 62188942Sthompsa/* BEGIN_MIB */ 63188942SthompsaSYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, 64188942Sthompsa "Sysctl internal magic"); 65188942SthompsaSYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, 66188942Sthompsa "High kernel, proc, limits &c"); 67188942SthompsaSYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, 68184610Salfred "Virtual memory"); 69188942SthompsaSYSCTL_NODE(, CTL_FS, fs, CTLFLAG_RW, 0, 70188942Sthompsa "File system"); 71184610SalfredSYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, 72190191Sthompsa "Network, (see socket.h)"); 73190191SthompsaSYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, 74184610Salfred "Debugging"); 75184610SalfredSYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, 76184610Salfred "hardware"); 77184610SalfredSYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, 78184610Salfred "machine dependent"); 79184610SalfredSYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, 80184610Salfred "user-level"); 81184610Salfred 82193045SthompsaSYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, ""); 83193045Sthompsa 84207080SthompsaSYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, ""); 85207080Sthompsa 86193045SthompsaSYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, ""); 87193045Sthompsa 88207080SthompsaSYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, ""); 89184610Salfred 90193045Sthompsaextern int osreldate; 91193045SthompsaSYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, ""); 92193045Sthompsa 93193045SthompsaSYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, ""); 94193045Sthompsa 95193045SthompsaSYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, ""); 96193045Sthompsa 97184610SalfredSYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, 98192984Sthompsa CTLFLAG_RD, &maxprocperuid, 0, ""); 99192984Sthompsa 100192984SthompsaSYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, 101192984Sthompsa CTLFLAG_RD, &maxfilesperproc, 0, ""); 102192984Sthompsa 103192984SthompsaSYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, ""); 104192984Sthompsa 105192984SthompsaSYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, ""); 106192984Sthompsa 107194228SthompsaSYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, ""); 108192984Sthompsa 109192984SthompsaSYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, ""); 110192984Sthompsa 111192984SthompsaSYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, ""); 112192984Sthompsa 113184610Salfred#ifdef _POSIX_SAVED_IDS 114184610SalfredSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, ""); 115184610Salfred#else 116194228SthompsaSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, ""); 117184610Salfred#endif 118184610Salfred 119184610Salfredchar kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ 120185087Salfred 121184610SalfredSYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, 122184610Salfred CTLFLAG_RW, kernelname, sizeof kernelname, ""); 123184610Salfred 124184610SalfredSYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, 125184610Salfred CTLFLAG_RW, &boottime, timeval, ""); 126184610Salfred 127194677SthompsaSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); 128184610Salfred 129184610SalfredSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); 130192502Sthompsa 131192502SthompsaSYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, ""); 132184610Salfred 133199675SthompsaSYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, ""); 134199675Sthompsa 135184610SalfredSYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, ""); 136184610Salfred 137184610Salfred/* END_MIB */ 138184610Salfred 139184610Salfredextern int vfs_update_wakeup; 140184610Salfredextern int vfs_update_interval; 141192984Sthompsastatic int 142192984Sthompsasysctl_kern_updateinterval SYSCTL_HANDLER_ARGS 143184610Salfred{ 144194677Sthompsa int error = sysctl_handle_int(oidp, 145192984Sthompsa oidp->oid_arg1, oidp->oid_arg2, 146193644Sthompsa oldp, oldlenp, newp, newlen); 147184610Salfred if (!error) 148184610Salfred wakeup(&vfs_update_wakeup); 149184610Salfred return error; 150184610Salfred} 151184610Salfred 152194228SthompsaSYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW, 153184610Salfred &vfs_update_interval, 0, sysctl_kern_updateinterval, ""); 154184610Salfred 155194228Sthompsa 156184610Salfredchar hostname[MAXHOSTNAMELEN]; 157184610Salfredint hostnamelen; 158184610Salfredstatic int 159184610Salfredsysctl_kern_hostname SYSCTL_HANDLER_ARGS 160194228Sthompsa{ 161184610Salfred int error = sysctl_handle_string(oidp, 162184610Salfred oidp->oid_arg1, oidp->oid_arg2, 163194228Sthompsa oldp, oldlenp, newp, newlen); 164184610Salfred if (newp && (error == 0 || error == ENOMEM)) 165184610Salfred hostnamelen = newlen; 166184610Salfred return error; 167184610Salfred} 168194228Sthompsa 169184610SalfredSYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW, 170184610Salfred &hostname, sizeof(hostname), sysctl_kern_hostname, ""); 171184610Salfred 172184610Salfredstatic int 173184610Salfredsysctl_order_cmp(const void *a, const void *b) 174184610Salfred{ 175184610Salfred const struct sysctl_oid **pa, **pb; 176184610Salfred 177192984Sthompsa pa = (const struct sysctl_oid **)a; 178184610Salfred pb = (const struct sysctl_oid **)b; 179194677Sthompsa if (*pa == NULL) 180193644Sthompsa return (1); 181184610Salfred if (*pb == NULL) 182184610Salfred return (-1); 183184610Salfred return ((*pa)->oid_number - (*pb)->oid_number); 184184610Salfred} 185184610Salfred 186194228Sthompsastatic void 187187180Sthompsasysctl_order(void *arg) 188187180Sthompsa{ 189187180Sthompsa int j; 190187180Sthompsa struct linker_set *l = (struct linker_set *) arg; 191187180Sthompsa struct sysctl_oid **oidpp; 192187180Sthompsa 193184610Salfred j = l->ls_length; 194184610Salfred oidpp = (struct sysctl_oid **) l->ls_items; 195187180Sthompsa for (; j--; oidpp++) { 196184610Salfred if (!*oidpp) 197184610Salfred continue; 198184610Salfred if ((*oidpp)->oid_arg1 == arg) { 199184610Salfred *oidpp = 0; 200184610Salfred continue; 201184610Salfred } 202184610Salfred if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 203184610Salfred if (!(*oidpp)->oid_handler) 204184610Salfred sysctl_order((*oidpp)->oid_arg1); 205184610Salfred } 206184610Salfred qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 207184610Salfred sysctl_order_cmp); 208184610Salfred} 209184610Salfred 210184610SalfredSYSINIT(sysctl,SI_SUB_KMEM,SI_ORDER_ANY,sysctl_order,&sysctl_); 211192984Sthompsa 212184610Salfredstatic void 213184610Salfredsysctl_sysctl_debug_dump_node(struct linker_set *l,int i) 214184610Salfred{ 215184610Salfred int j,k; 216184610Salfred struct sysctl_oid **oidpp; 217184610Salfred 218194228Sthompsa j = l->ls_length; 219194228Sthompsa oidpp = (struct sysctl_oid **) l->ls_items; 220184610Salfred for (; j--; oidpp++) { 221184610Salfred 222194228Sthompsa if (!*oidpp) 223194228Sthompsa continue; 224184610Salfred 225184610Salfred for (k=0; k<i; k++) 226184610Salfred printf(" "); 227185290Salfred 228184610Salfred if ((*oidpp)->oid_number > 100) { 229184610Salfred printf("Junk! %p # %d %s k %x a1 %p a2 %x h %p\n", 230184610Salfred *oidpp, 231184610Salfred (*oidpp)->oid_number, (*oidpp)->oid_name, 232192984Sthompsa (*oidpp)->oid_kind, (*oidpp)->oid_arg1, 233184610Salfred (*oidpp)->oid_arg2, (*oidpp)->oid_handler); 234192984Sthompsa continue; 235194677Sthompsa } 236193644Sthompsa printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 237184610Salfred 238184610Salfred printf("%c%c", 239184610Salfred (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 240184610Salfred (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 241184610Salfred 242184610Salfred switch ((*oidpp)->oid_kind & CTLTYPE) { 243184610Salfred case CTLTYPE_NODE: 244192984Sthompsa if ((*oidpp)->oid_handler) { 245184610Salfred printf(" Node(proc)\n"); 246192984Sthompsa } else { 247192984Sthompsa printf(" Node\n"); 248192984Sthompsa sysctl_sysctl_debug_dump_node( 249192984Sthompsa (*oidpp)->oid_arg1,i+2); 250192984Sthompsa } 251192984Sthompsa break; 252192984Sthompsa case CTLTYPE_INT: printf(" Int\n"); break; 253192984Sthompsa case CTLTYPE_STRING: printf(" String\n"); break; 254184610Salfred case CTLTYPE_QUAD: printf(" Quad\n"); break; 255192984Sthompsa case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 256192984Sthompsa default: printf("\n"); 257192984Sthompsa } 258192984Sthompsa 259192984Sthompsa } 260192984Sthompsa} 261184610Salfred 262184610Salfred 263184610Salfredstatic int 264184610Salfredsysctl_sysctl_debug SYSCTL_HANDLER_ARGS 265184610Salfred{ 266192984Sthompsa sysctl_sysctl_debug_dump_node(&sysctl_,0); 267184610Salfred return ENOENT; 268207080Sthompsa} 269192984Sthompsa 270192984SthompsaSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 271192984Sthompsa 0, 0, sysctl_sysctl_debug, ""); 272192984Sthompsa 273184610Salfredchar domainname[MAXHOSTNAMELEN]; 274184610Salfredint domainnamelen; 275184610Salfredstatic int 276184610Salfredsysctl_kern_domainname SYSCTL_HANDLER_ARGS 277184610Salfred{ 278184610Salfred int error = sysctl_handle_string(oidp, 279184610Salfred oidp->oid_arg1, oidp->oid_arg2, 280192984Sthompsa oldp, oldlenp, newp, newlen); 281192984Sthompsa if (newp && (error == 0 || error == ENOMEM)) 282192984Sthompsa domainnamelen = newlen; 283192984Sthompsa return error; 284192984Sthompsa} 285184610Salfred 286184610SalfredSYSCTL_PROC(_kern, KERN_DOMAINNAME, domainname, CTLTYPE_STRING|CTLFLAG_RW, 287192984Sthompsa &domainname, sizeof(domainname), sysctl_kern_domainname, ""); 288184610Salfred 289192984Sthompsalong hostid; 290184610Salfred/* Some trouble here, if sizeof (int) != sizeof (long) */ 291184610SalfredSYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, ""); 292184610Salfred 293184610Salfredint 294184610Salfredsysctl_handle_int SYSCTL_HANDLER_ARGS 295184610Salfred{ 296184610Salfred /* If there isn't sufficient space to return */ 297184610Salfred if (oldp && *oldlenp < sizeof(int)) 298184610Salfred return (ENOMEM); 299184610Salfred 300192984Sthompsa /* If it is a constant, don't write */ 301184610Salfred if (newp && !arg1) 302192984Sthompsa return (EPERM); 303194677Sthompsa 304193644Sthompsa /* If we get more than an int */ 305184610Salfred if (newp && newlen != sizeof(int)) 306184610Salfred return (EINVAL); 307184610Salfred 308184610Salfred *oldlenp = sizeof(int); 309184610Salfred if (oldp && arg1 ) 310184610Salfred bcopy(arg1, oldp, sizeof(int)); 311184610Salfred else if (oldp) 312192984Sthompsa bcopy(&arg2, oldp, sizeof(int)); 313184610Salfred if (newp) 314192984Sthompsa bcopy(newp, arg1, sizeof(int)); 315192984Sthompsa return (0); 316192984Sthompsa} 317192984Sthompsa 318192984Sthompsaint 319192984Sthompsasysctl_handle_string SYSCTL_HANDLER_ARGS 320192984Sthompsa{ 321192984Sthompsa int len, error=0; 322184610Salfred char *str = (char *)arg1; 323192984Sthompsa 324192984Sthompsa len = strlen(str) + 1; 325192984Sthompsa 326192984Sthompsa if (oldp && *oldlenp < len) { 327192984Sthompsa len = *oldlenp; 328192984Sthompsa error=ENOMEM; 329184610Salfred } 330184610Salfred 331184610Salfred if (newp && newlen >= arg2) 332184610Salfred return (EINVAL); 333184610Salfred 334192984Sthompsa if (oldp) { 335184610Salfred *oldlenp = len; 336192984Sthompsa bcopy(str, oldp, len); 337192984Sthompsa } 338207080Sthompsa 339192984Sthompsa if (newp) { 340184610Salfred bcopy(newp, str, newlen); 341192984Sthompsa str[newlen] = 0; 342184610Salfred } 343184610Salfred return (error); 344184610Salfred} 345184610Salfred 346184610Salfredint 347184610Salfredsysctl_handle_opaque SYSCTL_HANDLER_ARGS 348184610Salfred{ 349192984Sthompsa if (oldp && *oldlenp < arg2) 350192984Sthompsa return (ENOMEM); 351192984Sthompsa 352192984Sthompsa if (newp && newlen != arg2) 353192984Sthompsa return (EINVAL); 354184610Salfred 355184610Salfred if (oldp) { 356192984Sthompsa *oldlenp = arg2; 357184610Salfred bcopy(arg1, oldp, arg2); 358192984Sthompsa } 359184610Salfred if (newp) 360184610Salfred bcopy(newp, arg1, arg2); 361184610Salfred return (0); 362184610Salfred} 363184610Salfred 364184610Salfred#ifdef DEBUG 365184610Salfredstatic sysctlfn debug_sysctl; 366184610Salfred#endif 367184610Salfred 368184610Salfred/* 369184610Salfred * Locking and stats 370192984Sthompsa */ 371184610Salfredstatic struct sysctl_lock { 372184610Salfred int sl_lock; 373184610Salfred int sl_want; 374184610Salfred int sl_locked; 375194228Sthompsa} memlock; 376184610Salfred 377184610Salfred 378194228Sthompsa 379194228Sthompsa/* 380184610Salfred * Traverse our tree, and find the right node, execute whatever it points 381184610Salfred * at, and return the resulting error code. 382184610Salfred * We work entirely in kernel-space at this time. 383192984Sthompsa */ 384184610Salfred 385184610Salfred 386184610Salfredint 387184610Salfredsysctl_root SYSCTL_HANDLER_ARGS 388194228Sthompsa{ 389184610Salfred int *name = (int *) arg1; 390184610Salfred int namelen = arg2; 391194228Sthompsa int indx, i, j; 392194228Sthompsa struct sysctl_oid **oidpp; 393184610Salfred struct linker_set *lsp = &sysctl_; 394184610Salfred 395184610Salfred j = lsp->ls_length; 396192984Sthompsa oidpp = (struct sysctl_oid **) lsp->ls_items; 397184610Salfred 398184610Salfred indx = 0; 399194228Sthompsa while (j-- && indx < CTL_MAXNAME) { 400194228Sthompsa if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 401184610Salfred indx++; 402184610Salfred if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 403184610Salfred if ((*oidpp)->oid_handler) 404207080Sthompsa goto found; 405184610Salfred if (indx == namelen) 406194677Sthompsa return ENOENT; 407192984Sthompsa lsp = (struct linker_set*)(*oidpp)->oid_arg1; 408184610Salfred j = lsp->ls_length; 409184610Salfred oidpp = (struct sysctl_oid **)lsp->ls_items; 410184610Salfred } else { 411184610Salfred if (indx != namelen) 412184610Salfred return EISDIR; 413184610Salfred goto found; 414184610Salfred } 415184610Salfred } else { 416184610Salfred oidpp++; 417184610Salfred } 418184610Salfred } 419184610Salfred return EJUSTRETURN; 420184610Salfredfound: 421184610Salfred 422184610Salfred /* If writing isn't allowed */ 423184610Salfred if (newp && !((*oidpp)->oid_kind & CTLFLAG_WR)) 424184610Salfred return (EPERM); 425184610Salfred 426184610Salfred if (!(*oidpp)->oid_handler) 427184610Salfred return EINVAL; 428194228Sthompsa 429184610Salfred if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 430184610Salfred i = ((*oidpp)->oid_handler) (*oidpp, 431184610Salfred name + indx, namelen - indx, 432184610Salfred oldp, oldlenp, newp, newlen); 433194228Sthompsa } else { 434184610Salfred i = ((*oidpp)->oid_handler) (*oidpp, 435184610Salfred (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 436184610Salfred oldp, oldlenp, newp, newlen); 437184610Salfred } 438194677Sthompsa return (i); 439194228Sthompsa} 440184610Salfred 441184610Salfredstruct sysctl_args { 442184610Salfred int *name; 443184610Salfred u_int namelen; 444184610Salfred void *old; 445190188Sthompsa size_t *oldlenp; 446194228Sthompsa void *new; 447184610Salfred size_t newlen; 448184610Salfred}; 449194228Sthompsa 450184610Salfredint 451184610Salfred__sysctl(p, uap, retval) 452184610Salfred struct proc *p; 453184610Salfred register struct sysctl_args *uap; 454184610Salfred int *retval; 455184610Salfred{ 456207080Sthompsa int error, name[CTL_MAXNAME]; 457184610Salfred 458194677Sthompsa if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 459193045Sthompsa return (EINVAL); 460184610Salfred 461184610Salfred error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 462184610Salfred if (error) 463184610Salfred return (error); 464184610Salfred 465184610Salfred return (userland_sysctl(p, name, uap->namelen, 466184610Salfred uap->old, uap->oldlenp, 0, 467184610Salfred uap->new, uap->newlen, retval)); 468184610Salfred} 469184610Salfred 470184610Salfredstatic sysctlfn kern_sysctl; 471194228Sthompsa 472184610Salfred/* 473184610Salfred * This is used from various compatibility syscalls too. That's why name 474184610Salfred * must be in kernel space. 475184610Salfred */ 476184610Salfredint 477194228Sthompsauserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval) 478184610Salfred{ 479194677Sthompsa int error = 0, dolock = 1, i; 480194228Sthompsa u_int savelen = 0, oldlen = 0; 481184610Salfred sysctlfn *fn; 482184610Salfred void *oldp = 0; 483184610Salfred void *newp = 0; 484184610Salfred 485184610Salfred if (new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 486184610Salfred return (error); 487194228Sthompsa 488184610Salfred if (oldlenp) { 489184610Salfred if (inkernel) { 490184610Salfred oldlen = *oldlenp; 491184610Salfred } else { 492184610Salfred error = copyin(oldlenp, &oldlen, sizeof(oldlen)); 493184610Salfred if (error) 494194677Sthompsa return (error); 495184610Salfred } 496194677Sthompsa } 497192984Sthompsa 498184610Salfred if (old) 499184610Salfred oldp = malloc(oldlen, M_TEMP, M_WAITOK); 500184610Salfred 501184610Salfred if (newlen) { 502184610Salfred newp = malloc(newlen, M_TEMP, M_WAITOK); 503194228Sthompsa error = copyin(new, newp, newlen); 504184610Salfred } 505184610Salfred if (error) { 506194228Sthompsa if (oldp) 507184610Salfred free(oldp, M_TEMP); 508184610Salfred if (newp) 509184610Salfred free(newp, M_TEMP); 510184610Salfred return error; 511194677Sthompsa } 512184610Salfred 513194677Sthompsa error = sysctl_root(0, name, namelen, oldp, &oldlen, newp, newlen); 514192984Sthompsa 515184610Salfred if (!error || error == ENOMEM) { 516184610Salfred if (retval) 517184610Salfred *retval = oldlen; 518184610Salfred if (oldlenp) { 519184610Salfred if (inkernel) { 520194228Sthompsa *oldlenp = oldlen; 521184610Salfred } else { 522184610Salfred i = copyout(&oldlen, oldlenp, sizeof(oldlen)); 523194228Sthompsa if (i) 524184610Salfred error = i; 525184610Salfred } 526184610Salfred } 527184610Salfred if ((error == ENOMEM || !error ) && oldp) { 528194677Sthompsa i = copyout(oldp, old, oldlen); 529184610Salfred if (i) 530194677Sthompsa error = i; 531193045Sthompsa free(oldp, M_TEMP); 532193045Sthompsa } 533184610Salfred if (newp) 534184610Salfred free(newp, M_TEMP); 535184610Salfred return (error); 536184610Salfred } 537184610Salfred 538184610Salfred if (oldp) 539184610Salfred free(oldp, M_TEMP); 540184610Salfred if (newp) 541184610Salfred free(newp, M_TEMP); 542184610Salfred 543184610Salfred switch (name[0]) { 544194228Sthompsa case CTL_KERN: 545184610Salfred fn = kern_sysctl; 546184610Salfred if (name[1] != KERN_VNODE) /* XXX */ 547184610Salfred dolock = 0; 548184610Salfred break; 549184610Salfred case CTL_HW: 550184610Salfred fn = hw_sysctl; 551184610Salfred break; 552184610Salfred case CTL_VM: 553194677Sthompsa fn = vm_sysctl; 554184610Salfred break; 555194228Sthompsa case CTL_NET: 556184610Salfred fn = net_sysctl; 557184610Salfred break; 558184610Salfred case CTL_FS: 559184610Salfred fn = fs_sysctl; 560184610Salfred break; 561184610Salfred#ifdef DEBUG 562184610Salfred case CTL_DEBUG: 563184610Salfred fn = debug_sysctl; 564184610Salfred break; 565184610Salfred#endif 566184610Salfred default: 567194677Sthompsa return (EOPNOTSUPP); 568184610Salfred } 569194677Sthompsa if (old != NULL) { 570193045Sthompsa if (!useracc(old, oldlen, B_WRITE)) 571193045Sthompsa return (EFAULT); 572193045Sthompsa while (memlock.sl_lock) { 573184610Salfred memlock.sl_want = 1; 574184610Salfred (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 575184610Salfred memlock.sl_locked++; 576184610Salfred } 577184610Salfred memlock.sl_lock = 1; 578184610Salfred if (dolock) 579184610Salfred vslock(old, oldlen); 580184610Salfred savelen = oldlen; 581184610Salfred } 582194228Sthompsa 583184610Salfred 584194677Sthompsa error = (*fn)(name + 1, namelen - 1, old, &oldlen, 585184610Salfred new, newlen, p); 586184610Salfred 587184610Salfred 588184610Salfred if (old != NULL) { 589184610Salfred if (dolock) 590184610Salfred vsunlock(old, savelen, B_WRITE); 591184610Salfred memlock.sl_lock = 0; 592184610Salfred if (memlock.sl_want) { 593194677Sthompsa memlock.sl_want = 0; 594184610Salfred wakeup((caddr_t)&memlock); 595194228Sthompsa } 596184610Salfred } 597184610Salfred#if 0 598184610Salfred if (error) { 599184610Salfred printf("SYSCTL_ERROR: "); 600184610Salfred for(i=0;i<namelen;i++) 601184610Salfred printf("%d ", name[i]); 602184610Salfred printf("= %d\n", error); 603184610Salfred } 604184610Salfred#endif 605184610Salfred if (error) 606184610Salfred return (error); 607192984Sthompsa if (retval) 608184610Salfred *retval = oldlen; 609184610Salfred if (oldlenp) { 610184610Salfred if (inkernel) { 611192499Sthompsa *oldlenp = oldlen; 612184610Salfred } else { 613184610Salfred error = copyout(&oldlen, oldlenp, sizeof(oldlen)); 614184610Salfred } 615184610Salfred } 616184610Salfred return (error); 617184610Salfred} 618184610Salfred 619185290Salfred/* 620185290Salfred * Attributes stored in the kernel. 621185290Salfred */ 622185290Salfredint securelevel = -1; 623185290Salfred 624185290Salfred/* 625184610Salfred * kernel related system variables. 626194228Sthompsa */ 627184610Salfredstatic int 628184610Salfredkern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 629184610Salfred int *name; 630194228Sthompsa u_int namelen; 631184610Salfred void *oldp; 632184610Salfred size_t *oldlenp; 633184610Salfred void *newp; 634184610Salfred size_t newlen; 635184610Salfred struct proc *p; 636184610Salfred{ 637192984Sthompsa int error, level; 638184610Salfred dev_t ndumpdev; 639184610Salfred 640184610Salfred /* all sysctl names at this level are terminal */ 641184610Salfred if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF 642192499Sthompsa || name[0] == KERN_NTP_PLL)) 643184610Salfred return (ENOTDIR); /* overloaded */ 644184610Salfred 645184610Salfred switch (name[0]) { 646185290Salfred 647185290Salfred case KERN_SECURELVL: 648185290Salfred level = securelevel; 649185290Salfred if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 650185290Salfred newp == NULL) 651185290Salfred return (error); 652184610Salfred if (level < securelevel && p->p_pid != 1) 653194228Sthompsa return (EPERM); 654184610Salfred securelevel = level; 655184610Salfred return (0); 656184610Salfred case KERN_VNODE: 657194228Sthompsa return (sysctl_vnode(oldp, oldlenp)); 658184610Salfred case KERN_PROC: 659184610Salfred return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 660184610Salfred case KERN_FILE: 661184610Salfred return (sysctl_file(oldp, oldlenp)); 662184610Salfred#ifdef GPROF 663184610Salfred case KERN_PROF: 664184610Salfred return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 665184610Salfred newp, newlen)); 666184610Salfred#endif 667184610Salfred case KERN_NTP_PLL: 668184610Salfred return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp, 669184610Salfred newp, newlen, p)); 670192984Sthompsa case KERN_DUMPDEV: 671184610Salfred ndumpdev = dumpdev; 672192984Sthompsa error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev, 673192984Sthompsa sizeof ndumpdev); 674184610Salfred if (!error && ndumpdev != dumpdev) { 675184610Salfred error = setdumpdev(ndumpdev); 676184610Salfred } 677184610Salfred return error; 678184610Salfred default: 679184610Salfred return (EOPNOTSUPP); 680184610Salfred } 681184610Salfred /* NOTREACHED */ 682184610Salfred} 683184610Salfred 684184610Salfred/* 685184610Salfred * hardware related system variables. 686194228Sthompsa */ 687184610Salfredint 688184610Salfredhw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 689184610Salfred int *name; 690184610Salfred u_int namelen; 691184610Salfred void *oldp; 692184610Salfred size_t *oldlenp; 693194228Sthompsa void *newp; 694188986Sthompsa size_t newlen; 695184610Salfred struct proc *p; 696184610Salfred{ 697184610Salfred /* almost all sysctl names at this level are terminal */ 698184610Salfred if (namelen != 1 && name[0] != HW_DEVCONF) 699184610Salfred return (ENOTDIR); /* overloaded */ 700184610Salfred 701184610Salfred switch (name[0]) { 702184610Salfred case HW_PHYSMEM: 703184610Salfred return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 704184610Salfred case HW_USERMEM: 705184610Salfred return (sysctl_rdint(oldp, oldlenp, newp, 706184610Salfred ctob(physmem - cnt.v_wire_count))); 707184610Salfred case HW_DEVCONF: 708184610Salfred return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp, 709184610Salfred newp, newlen, p)); 710184610Salfred default: 711184610Salfred return (EOPNOTSUPP); 712184610Salfred } 713184610Salfred /* NOTREACHED */ 714184610Salfred} 715184610Salfred 716184610Salfred#ifdef DEBUG 717184610Salfred/* 718184610Salfred * Debugging related system variables. 719192984Sthompsa */ 720184610Salfredstruct ctldebug debug0, debug1, debug2, debug3, debug4; 721184610Salfredstruct ctldebug debug5, debug6, debug7, debug8, debug9; 722184610Salfredstruct ctldebug debug10, debug11, debug12, debug13, debug14; 723184610Salfredstruct ctldebug debug15, debug16, debug17, debug18, debug19; 724184610Salfredstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 725194228Sthompsa &debug0, &debug1, &debug2, &debug3, &debug4, 726184610Salfred &debug5, &debug6, &debug7, &debug8, &debug9, 727184610Salfred &debug10, &debug11, &debug12, &debug13, &debug14, 728184610Salfred &debug15, &debug16, &debug17, &debug18, &debug19, 729184610Salfred}; 730184610Salfredstatic int 731184610Salfreddebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 732184610Salfred int *name; 733184610Salfred u_int namelen; 734184610Salfred void *oldp; 735184610Salfred size_t *oldlenp; 736184610Salfred void *newp; 737184610Salfred size_t newlen; 738184610Salfred struct proc *p; 739184610Salfred{ 740184610Salfred struct ctldebug *cdp; 741184610Salfred 742184610Salfred /* all sysctl names at this level are name and field */ 743184610Salfred if (namelen != 2) 744184610Salfred return (ENOTDIR); /* overloaded */ 745188622Sthompsa cdp = debugvars[name[0]]; 746184610Salfred if (cdp->debugname == 0) 747188622Sthompsa return (EOPNOTSUPP); 748184610Salfred switch (name[1]) { 749184610Salfred case CTL_DEBUG_NAME: 750184610Salfred return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 751184610Salfred case CTL_DEBUG_VALUE: 752184610Salfred return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 753184610Salfred default: 754192984Sthompsa return (EOPNOTSUPP); 755184610Salfred } 756192984Sthompsa /* NOTREACHED */ 757192984Sthompsa} 758184610Salfred#endif /* DEBUG */ 759188622Sthompsa 760188622Sthompsa/* 761188622Sthompsa * Validate parameters and get old / set new parameters 762188622Sthompsa * for an integer-valued sysctl function. 763188622Sthompsa */ 764184610Salfredint 765188622Sthompsasysctl_int(oldp, oldlenp, newp, newlen, valp) 766184610Salfred void *oldp; 767188622Sthompsa size_t *oldlenp; 768188622Sthompsa void *newp; 769184610Salfred size_t newlen; 770184610Salfred int *valp; 771188622Sthompsa{ 772194228Sthompsa int error = 0; 773188622Sthompsa 774188622Sthompsa if (oldp && *oldlenp < sizeof(int)) 775188622Sthompsa return (ENOMEM); 776184610Salfred if (newp && newlen != sizeof(int)) 777188622Sthompsa return (EINVAL); 778188622Sthompsa *oldlenp = sizeof(int); 779188622Sthompsa if (oldp) 780188622Sthompsa error = copyout(valp, oldp, sizeof(int)); 781188622Sthompsa if (error == 0 && newp) 782188622Sthompsa error = copyin(newp, valp, sizeof(int)); 783188622Sthompsa return (error); 784188622Sthompsa} 785188622Sthompsa 786188622Sthompsa/* 787188622Sthompsa * As above, but read-only. 788188622Sthompsa */ 789188622Sthompsaint 790188622Sthompsasysctl_rdint(oldp, oldlenp, newp, val) 791188622Sthompsa void *oldp; 792188622Sthompsa size_t *oldlenp; 793188622Sthompsa void *newp; 794188622Sthompsa int val; 795188622Sthompsa{ 796188622Sthompsa int error = 0; 797188622Sthompsa 798188622Sthompsa if (oldp && *oldlenp < sizeof(int)) 799188622Sthompsa return (ENOMEM); 800188622Sthompsa if (newp) 801184610Salfred return (EPERM); 802188622Sthompsa *oldlenp = sizeof(int); 803184610Salfred if (oldp) 804184610Salfred error = copyout((caddr_t)&val, oldp, sizeof(int)); 805184610Salfred return (error); 806194228Sthompsa} 807184610Salfred 808184610Salfred/* 809184610Salfred * Validate parameters and get old / set new parameters 810184610Salfred * for a string-valued sysctl function. 811184610Salfred */ 812184610Salfredint 813184610Salfredsysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 814184610Salfred void *oldp; 815184610Salfred size_t *oldlenp; 816194228Sthompsa void *newp; 817184610Salfred size_t newlen; 818192984Sthompsa char *str; 819192984Sthompsa int maxlen; 820184610Salfred{ 821184610Salfred int len, error = 0, rval = 0; 822184610Salfred 823184610Salfred len = strlen(str) + 1; 824184610Salfred if (oldp && *oldlenp < len) { 825184610Salfred len = *oldlenp; 826184610Salfred rval = ENOMEM; 827184610Salfred } 828192938Sthompsa if (newp && newlen >= maxlen) 829192938Sthompsa return (EINVAL); 830192938Sthompsa if (oldp) { 831194228Sthompsa *oldlenp = len; 832184610Salfred error = copyout(str, oldp, len); 833184610Salfred if (error) 834184610Salfred rval = error; 835184610Salfred } 836184610Salfred if ((error == 0 || error == ENOMEM) && newp) { 837184610Salfred error = copyin(newp, str, newlen); 838184610Salfred if (error) 839184610Salfred rval = error; 840184610Salfred str[newlen] = 0; 841184610Salfred } 842184610Salfred return (rval); 843192499Sthompsa} 844184610Salfred 845191824Sthompsa/* 846184610Salfred * As above, but read-only. 847184610Salfred */ 848184610Salfredint 849184610Salfredsysctl_rdstring(oldp, oldlenp, newp, str) 850184610Salfred void *oldp; 851184610Salfred size_t *oldlenp; 852184610Salfred void *newp; 853184610Salfred char *str; 854184610Salfred{ 855184610Salfred int len, error = 0, rval = 0; 856184610Salfred 857184610Salfred len = strlen(str) + 1; 858184610Salfred if (oldp && *oldlenp < len) { 859184610Salfred len = *oldlenp; 860184610Salfred rval = ENOMEM; 861184610Salfred } 862184610Salfred if (newp) 863184610Salfred return (EPERM); 864192984Sthompsa *oldlenp = len; 865184610Salfred if (oldp) 866193644Sthompsa error = copyout(str, oldp, len); 867184610Salfred if (error) 868184610Salfred rval = error; 869184610Salfred return (rval); 870184610Salfred} 871184610Salfred 872184610Salfred/* 873184610Salfred * Validate parameters and get old / set new parameters 874184610Salfred * for a structure oriented sysctl function. 875184610Salfred */ 876184610Salfredint 877184610Salfredsysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 878184610Salfred void *oldp; 879184610Salfred size_t *oldlenp; 880184610Salfred void *newp; 881184610Salfred size_t newlen; 882184610Salfred void *sp; 883184610Salfred int len; 884184610Salfred{ 885184610Salfred int error = 0; 886184610Salfred 887184610Salfred if (oldp && *oldlenp < len) 888184610Salfred return (ENOMEM); 889184610Salfred if (newp && newlen > len) 890184610Salfred return (EINVAL); 891194228Sthompsa if (oldp) { 892193644Sthompsa *oldlenp = len; 893184610Salfred error = copyout(sp, oldp, len); 894184610Salfred } 895184610Salfred if (error == 0 && newp) 896184610Salfred error = copyin(newp, sp, len); 897194228Sthompsa return (error); 898184610Salfred} 899184610Salfred 900184610Salfred/* 901184610Salfred * Validate parameters and get old parameters 902184610Salfred * for a structure oriented sysctl function. 903184610Salfred */ 904184610Salfredint 905184610Salfredsysctl_rdstruct(oldp, oldlenp, newp, sp, len) 906192984Sthompsa void *oldp; 907184610Salfred size_t *oldlenp; 908184610Salfred void *newp, *sp; 909184610Salfred int len; 910184610Salfred{ 911184610Salfred int error = 0; 912184610Salfred 913184610Salfred if (oldp && *oldlenp < len) 914184610Salfred return (ENOMEM); 915184610Salfred if (newp) 916184610Salfred return (EPERM); 917184610Salfred *oldlenp = len; 918184610Salfred if (oldp) 919184610Salfred error = copyout(sp, oldp, len); 920184610Salfred return (error); 921184610Salfred} 922184610Salfred 923184610Salfred/* 924194228Sthompsa * Get file structures. 925184610Salfred */ 926184610Salfredint 927184610Salfredsysctl_file(where, sizep) 928184610Salfred char *where; 929184610Salfred size_t *sizep; 930184610Salfred{ 931184610Salfred int buflen, error; 932184610Salfred struct file *fp; 933184610Salfred char *start = where; 934184610Salfred 935184610Salfred buflen = *sizep; 936184610Salfred if (where == NULL) { 937184610Salfred /* 938184610Salfred * overestimate by 10 files 939184610Salfred */ 940184610Salfred *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 941184610Salfred return (0); 942192984Sthompsa } 943184610Salfred 944192984Sthompsa /* 945184610Salfred * first copyout filehead 946184610Salfred */ 947184610Salfred if (buflen < sizeof(filehead)) { 948184610Salfred *sizep = 0; 949184610Salfred return (0); 950184610Salfred } 951184610Salfred error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 952184610Salfred if (error) 953184610Salfred return (error); 954185087Salfred buflen -= sizeof(filehead); 955185087Salfred where += sizeof(filehead); 956185087Salfred 957185087Salfred /* 958185087Salfred * followed by an array of file structures 959185087Salfred */ 960184610Salfred for (fp = filehead; fp != NULL; fp = fp->f_filef) { 961194228Sthompsa if (buflen < sizeof(struct file)) { 962184610Salfred *sizep = where - start; 963184610Salfred return (ENOMEM); 964184610Salfred } 965184610Salfred error = copyout((caddr_t)fp, where, sizeof (struct file)); 966184610Salfred if (error) 967185087Salfred return (error); 968185087Salfred buflen -= sizeof(struct file); 969185087Salfred where += sizeof(struct file); 970185087Salfred } 971185087Salfred *sizep = where - start; 972184610Salfred return (0); 973184610Salfred} 974184610Salfred 975185087Salfred/* 976192984Sthompsa * try over estimating by 5 procs 977184610Salfred */ 978184610Salfred#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 979184610Salfred 980184610Salfredint 981194228Sthompsasysctl_doproc(name, namelen, where, sizep) 982184610Salfred int *name; 983184610Salfred u_int namelen; 984184610Salfred char *where; 985184610Salfred size_t *sizep; 986184610Salfred{ 987194228Sthompsa register struct proc *p; 988184610Salfred register struct kinfo_proc *dp = (struct kinfo_proc *)where; 989184610Salfred register int needed = 0; 990184610Salfred int buflen = where != NULL ? *sizep : 0; 991184610Salfred int doingzomb; 992192984Sthompsa struct eproc eproc; 993184610Salfred int error = 0; 994192984Sthompsa 995184610Salfred if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 996184610Salfred return (EINVAL); 997184610Salfred p = (struct proc *)allproc; 998184610Salfred doingzomb = 0; 999184610Salfredagain: 1000184610Salfred for (; p != NULL; p = p->p_next) { 1001184610Salfred /* 1002184610Salfred * Skip embryonic processes. 1003184610Salfred */ 1004184610Salfred if (p->p_stat == SIDL) 1005184610Salfred continue; 1006184610Salfred /* 1007184610Salfred * TODO - make more efficient (see notes below). 1008184610Salfred * do by session. 1009184610Salfred */ 1010184610Salfred switch (name[0]) { 1011184610Salfred 1012184610Salfred case KERN_PROC_PID: 1013184610Salfred /* could do this with just a lookup */ 1014192984Sthompsa if (p->p_pid != (pid_t)name[1]) 1015184610Salfred continue; 1016192984Sthompsa break; 1017184610Salfred 1018184610Salfred case KERN_PROC_PGRP: 1019184610Salfred /* could do this by traversing pgrp */ 1020184610Salfred if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1]) 1021184610Salfred continue; 1022184610Salfred break; 1023184610Salfred 1024184610Salfred case KERN_PROC_TTY: 1025184610Salfred if ((p->p_flag & P_CONTROLT) == 0 || 1026184610Salfred p->p_session == NULL || 1027184610Salfred p->p_session->s_ttyp == NULL || 1028184610Salfred p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 1029184610Salfred continue; 1030184610Salfred break; 1031184610Salfred 1032184610Salfred case KERN_PROC_UID: 1033194228Sthompsa if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1]) 1034184610Salfred continue; 1035184610Salfred break; 1036184610Salfred 1037192984Sthompsa case KERN_PROC_RUID: 1038184610Salfred if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1]) 1039192984Sthompsa continue; 1040192984Sthompsa break; 1041192984Sthompsa } 1042184610Salfred if (buflen >= sizeof(struct kinfo_proc)) { 1043184610Salfred fill_eproc(p, &eproc); 1044193045Sthompsa error = copyout((caddr_t)p, &dp->kp_proc, 1045193045Sthompsa sizeof(struct proc)); 1046193045Sthompsa if (error) 1047184610Salfred return (error); 1048184610Salfred error = copyout((caddr_t)&eproc, &dp->kp_eproc, 1049184610Salfred sizeof(eproc)); 1050184610Salfred if (error) 1051184610Salfred return (error); 1052184610Salfred dp++; 1053184610Salfred buflen -= sizeof(struct kinfo_proc); 1054184610Salfred } 1055184610Salfred needed += sizeof(struct kinfo_proc); 1056184610Salfred } 1057184610Salfred if (doingzomb == 0) { 1058184610Salfred p = zombproc; 1059194228Sthompsa doingzomb++; 1060184610Salfred goto again; 1061184610Salfred } 1062184610Salfred if (where != NULL) { 1063184610Salfred *sizep = (caddr_t)dp - where; 1064184610Salfred if (needed > *sizep) 1065184610Salfred return (ENOMEM); 1066184610Salfred } else { 1067184610Salfred needed += KERN_PROCSLOP; 1068184610Salfred *sizep = needed; 1069184610Salfred } 1070184610Salfred return (0); 1071184610Salfred} 1072184610Salfred 1073184610Salfred/* 1074184610Salfred * Fill in an eproc structure for the specified process. 1075184610Salfred */ 1076184610Salfredvoid 1077184610Salfredfill_eproc(p, ep) 1078184610Salfred register struct proc *p; 1079184610Salfred register struct eproc *ep; 1080184610Salfred{ 1081184610Salfred register struct tty *tp; 1082184610Salfred 1083184610Salfred bzero(ep, sizeof(*ep)); 1084184610Salfred 1085184610Salfred ep->e_paddr = p; 1086194677Sthompsa if (p->p_cred) { 1087184610Salfred ep->e_pcred = *p->p_cred; 1088184610Salfred if (p->p_ucred) 1089184610Salfred ep->e_ucred = *p->p_ucred; 1090184610Salfred } 1091184610Salfred if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) { 1092184610Salfred register struct vmspace *vm = p->p_vmspace; 1093184610Salfred 1094184610Salfred#ifdef pmap_resident_count 1095184610Salfred ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/ 1096184610Salfred#else 1097194659Sthompsa ep->e_vm.vm_rssize = vm->vm_rssize; 1098184610Salfred#endif 1099184610Salfred ep->e_vm.vm_tsize = vm->vm_tsize; 1100184610Salfred ep->e_vm.vm_dsize = vm->vm_dsize; 1101184610Salfred ep->e_vm.vm_ssize = vm->vm_ssize; 1102184610Salfred#ifndef sparc 1103184610Salfred ep->e_vm.vm_pmap = vm->vm_pmap; 1104184610Salfred#endif 1105184610Salfred } 1106184610Salfred if (p->p_pptr) 1107184610Salfred ep->e_ppid = p->p_pptr->p_pid; 1108184610Salfred if (p->p_pgrp) { 1109184610Salfred ep->e_sess = p->p_pgrp->pg_session; 1110184610Salfred ep->e_pgid = p->p_pgrp->pg_id; 1111194677Sthompsa ep->e_jobc = p->p_pgrp->pg_jobc; 1112184610Salfred } 1113184610Salfred if ((p->p_flag & P_CONTROLT) && 1114184610Salfred (ep->e_sess != NULL) && 1115184610Salfred ((tp = ep->e_sess->s_ttyp) != NULL)) { 1116184610Salfred ep->e_tdev = tp->t_dev; 1117184610Salfred ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 1118184610Salfred ep->e_tsess = tp->t_session; 1119184610Salfred } else 1120184610Salfred ep->e_tdev = NODEV; 1121184610Salfred if (ep->e_sess && ep->e_sess->s_ttyvp) 1122184610Salfred ep->e_flag = EPROC_CTTY; 1123184610Salfred if (SESS_LEADER(p)) 1124184610Salfred ep->e_flag |= EPROC_SLEADER; 1125184610Salfred if (p->p_wmesg) { 1126184610Salfred strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 1127184610Salfred ep->e_wmesg[WMESGLEN] = 0; 1128184610Salfred } 1129184610Salfred} 1130184610Salfred 1131184610Salfred#ifdef COMPAT_43 1132184610Salfred#include <sys/socket.h> 1133184610Salfred#define KINFO_PROC (0<<8) 1134194677Sthompsa#define KINFO_RT (1<<8) 1135184610Salfred#define KINFO_VNODE (2<<8) 1136184610Salfred#define KINFO_FILE (3<<8) 1137184610Salfred#define KINFO_METER (4<<8) 1138184610Salfred#define KINFO_LOADAVG (5<<8) 1139184610Salfred#define KINFO_CLOCKRATE (6<<8) 1140184610Salfred 1141184610Salfred/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 1142184610Salfred#define KINFO_BSDI_SYSINFO (101<<8) 1143184610Salfred 1144184610Salfred/* 1145184610Salfred * XXX this is bloat, but I hope it's better here than on the potentially 1146184610Salfred * limited kernel stack... -Peter 1147184610Salfred */ 1148184610Salfred 1149184610Salfredstruct { 1150184610Salfred int bsdi_machine; /* "i386" on BSD/386 */ 1151184610Salfred/* ^^^ this is an offset to the string, relative to the struct start */ 1152184610Salfred char *pad0; 1153184610Salfred long pad1; 1154184610Salfred long pad2; 1155184610Salfred long pad3; 1156194677Sthompsa u_long pad4; 1157184610Salfred u_long pad5; 1158184610Salfred u_long pad6; 1159184610Salfred 1160184610Salfred int bsdi_ostype; /* "BSD/386" on BSD/386 */ 1161184610Salfred int bsdi_osrelease; /* "1.1" on BSD/386 */ 1162184610Salfred long pad7; 1163184610Salfred long pad8; 1164184610Salfred char *pad9; 1165184610Salfred 1166184610Salfred long pad10; 1167194677Sthompsa long pad11; 1168184610Salfred int pad12; 1169184610Salfred long pad13; 1170184610Salfred quad_t pad14; 1171184610Salfred long pad15; 1172184610Salfred 1173184610Salfred struct timeval pad16; 1174184610Salfred /* we dont set this, because BSDI's uname used gethostname() instead */ 1175184610Salfred int bsdi_hostname; /* hostname on BSD/386 */ 1176184610Salfred 1177184610Salfred /* the actual string data is appended here */ 1178184610Salfred 1179184610Salfred} bsdi_si; 1180184610Salfred/* 1181184610Salfred * this data is appended to the end of the bsdi_si structure during copyout. 1182184610Salfred * The "char *" offsets are relative to the base of the bsdi_si struct. 1183184610Salfred * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 1184184610Salfred * should not exceed the length of the buffer here... (or else!! :-) 1185184610Salfred */ 1186184610Salfredchar bsdi_strings[80]; /* It had better be less than this! */ 1187184610Salfred 1188184610Salfredstruct getkerninfo_args { 1189194677Sthompsa int op; 1190184610Salfred char *where; 1191184610Salfred int *size; 1192184610Salfred int arg; 1193184610Salfred}; 1194184610Salfred 1195184610Salfredint 1196184610Salfredogetkerninfo(p, uap, retval) 1197184610Salfred struct proc *p; 1198184610Salfred register struct getkerninfo_args *uap; 1199184610Salfred int *retval; 1200184610Salfred{ 1201184610Salfred int error, name[6]; 1202184610Salfred u_int size; 1203184610Salfred 1204184610Salfred switch (uap->op & 0xff00) { 1205184610Salfred 1206184610Salfred case KINFO_RT: 1207184610Salfred name[0] = CTL_NET; 1208184610Salfred name[1] = PF_ROUTE; 1209184610Salfred name[2] = 0; 1210184610Salfred name[3] = (uap->op & 0xff0000) >> 16; 1211184610Salfred name[4] = uap->op & 0xff; 1212184610Salfred name[5] = uap->arg; 1213192984Sthompsa error = userland_sysctl(p, name, 6, uap->where, uap->size, 1214184610Salfred 0, 0, 0, 0); 1215192984Sthompsa break; 1216192984Sthompsa 1217192984Sthompsa case KINFO_VNODE: 1218192984Sthompsa name[0] = CTL_KERN; 1219184610Salfred name[1] = KERN_VNODE; 1220184610Salfred error = userland_sysctl(p, name, 2, uap->where, uap->size, 1221193045Sthompsa 0, 0, 0, 0); 1222193045Sthompsa break; 1223193045Sthompsa 1224184610Salfred case KINFO_PROC: 1225184610Salfred name[0] = CTL_KERN; 1226184610Salfred name[1] = KERN_PROC; 1227184610Salfred name[2] = uap->op & 0xff; 1228184610Salfred name[3] = uap->arg; 1229190181Sthompsa error = userland_sysctl(p, name, 4, uap->where, uap->size, 1230184610Salfred 0, 0, 0, 0); 1231190181Sthompsa break; 1232184610Salfred 1233190181Sthompsa case KINFO_FILE: 1234184610Salfred name[0] = CTL_KERN; 1235190181Sthompsa name[1] = KERN_FILE; 1236184610Salfred error = userland_sysctl(p, name, 2, uap->where, uap->size, 1237194228Sthompsa 0, 0, 0, 0); 1238184610Salfred break; 1239184610Salfred 1240184610Salfred case KINFO_METER: 1241184610Salfred name[0] = CTL_VM; 1242184610Salfred name[1] = VM_METER; 1243184610Salfred error = userland_sysctl(p, name, 2, uap->where, uap->size, 1244184610Salfred 0, 0, 0, 0); 1245184610Salfred break; 1246184610Salfred 1247184610Salfred case KINFO_LOADAVG: 1248184610Salfred name[0] = CTL_VM; 1249184610Salfred name[1] = VM_LOADAVG; 1250184610Salfred error = userland_sysctl(p, name, 2, uap->where, uap->size, 1251184610Salfred 0, 0, 0, 0); 1252184610Salfred break; 1253184610Salfred 1254184610Salfred case KINFO_CLOCKRATE: 1255184610Salfred name[0] = CTL_KERN; 1256184610Salfred name[1] = KERN_CLOCKRATE; 1257184610Salfred error = userland_sysctl(p, name, 2, uap->where, uap->size, 1258184610Salfred 0, 0, 0, 0); 1259184610Salfred break; 1260184610Salfred 1261184610Salfred case KINFO_BSDI_SYSINFO: { 1262184610Salfred /* 1263184610Salfred * this is pretty crude, but it's just enough for uname() 1264184610Salfred * from BSDI's 1.x libc to work. 1265184610Salfred * 1266184610Salfred * In particular, it doesn't return the same results when 1267184610Salfred * the supplied buffer is too small. BSDI's version apparently 1268184610Salfred * will return the amount copied, and set the *size to how 1269184610Salfred * much was needed. The emulation framework here isn't capable 1270184610Salfred * of that, so we just set both to the amount copied. 1271184610Salfred * BSDI's 2.x product apparently fails with ENOMEM in this 1272184610Salfred * scenario. 1273184610Salfred */ 1274184610Salfred 1275184610Salfred u_int needed; 1276184610Salfred u_int left; 1277184610Salfred char *s; 1278184610Salfred 1279194677Sthompsa bzero((char *)&bsdi_si, sizeof(bsdi_si)); 1280184610Salfred bzero(bsdi_strings, sizeof(bsdi_strings)); 1281184610Salfred 1282184610Salfred s = bsdi_strings; 1283184610Salfred 1284184610Salfred bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 1285184610Salfred strcpy(s, ostype); 1286184610Salfred s += strlen(s) + 1; 1287184610Salfred 1288184610Salfred bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 1289184610Salfred strcpy(s, osrelease); 1290184610Salfred s += strlen(s) + 1; 1291184610Salfred 1292184610Salfred bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 1293184610Salfred strcpy(s, machine); 1294184610Salfred s += strlen(s) + 1; 1295184610Salfred 1296184610Salfred needed = sizeof(bsdi_si) + (s - bsdi_strings); 1297184610Salfred 1298184610Salfred if (uap->where == NULL) { 1299184610Salfred /* process is asking how much buffer to supply.. */ 1300184610Salfred size = needed; 1301184610Salfred error = 0; 1302184610Salfred break; 1303184610Salfred } 1304184610Salfred 1305184610Salfred 1306184610Salfred /* if too much buffer supplied, trim it down */ 1307184610Salfred if (size > needed) 1308184610Salfred size = needed; 1309184610Salfred 1310184610Salfred /* how much of the buffer is remaining */ 1311184610Salfred left = size; 1312184610Salfred 1313184610Salfred if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 1314184610Salfred break; 1315184610Salfred 1316184610Salfred /* is there any point in continuing? */ 1317184610Salfred if (left > sizeof(bsdi_si)) { 1318184610Salfred left -= sizeof(bsdi_si); 1319184610Salfred error = copyout(&bsdi_strings, 1320184610Salfred uap->where + sizeof(bsdi_si), left); 1321184610Salfred } 1322184610Salfred break; 1323184610Salfred } 1324184610Salfred 1325184610Salfred default: 1326184610Salfred return (EOPNOTSUPP); 1327184610Salfred } 1328184610Salfred if (error) 1329184610Salfred return (error); 1330184610Salfred *retval = size; 1331184610Salfred if (uap->size) 1332184610Salfred error = copyout((caddr_t)&size, (caddr_t)uap->size, 1333184610Salfred sizeof(size)); 1334184610Salfred return (error); 1335184610Salfred} 1336184610Salfred#endif /* COMPAT_43 */ 1337184610Salfred