kern_sysctl.c revision 83968
11541Srgrimes/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Mike Karels at Berkeley Software Design, Inc. 71541Srgrimes * 812623Sphk * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD 912623Sphk * project, to make these variables more userfriendly. 1012623Sphk * 111541Srgrimes * Redistribution and use in source and binary forms, with or without 121541Srgrimes * modification, are permitted provided that the following conditions 131541Srgrimes * are met: 141541Srgrimes * 1. Redistributions of source code must retain the above copyright 151541Srgrimes * notice, this list of conditions and the following disclaimer. 161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171541Srgrimes * notice, this list of conditions and the following disclaimer in the 181541Srgrimes * documentation and/or other materials provided with the distribution. 191541Srgrimes * 3. All advertising materials mentioning features or use of this software 201541Srgrimes * must display the following acknowledgement: 211541Srgrimes * This product includes software developed by the University of 221541Srgrimes * California, Berkeley and its contributors. 231541Srgrimes * 4. Neither the name of the University nor the names of its contributors 241541Srgrimes * may be used to endorse or promote products derived from this software 251541Srgrimes * without specific prior written permission. 261541Srgrimes * 271541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 281541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 291541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 301541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 311541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 321541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 331541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 341541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 351541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 361541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 371541Srgrimes * SUCH DAMAGE. 381541Srgrimes * 391541Srgrimes * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 4050477Speter * $FreeBSD: head/sys/kern/kern_sysctl.c 83968 2001-09-26 19:51:25Z rwatson $ 411541Srgrimes */ 421541Srgrimes 4331778Seivind#include "opt_compat.h" 4431778Seivind 451541Srgrimes#include <sys/param.h> 4648274Speter#include <sys/systm.h> 4748274Speter#include <sys/kernel.h> 481541Srgrimes#include <sys/sysctl.h> 4912623Sphk#include <sys/malloc.h> 5012662Sdg#include <sys/proc.h> 5182746Sdillon#include <sys/lock.h> 5282746Sdillon#include <sys/mutex.h> 5315103Sphk#include <sys/sysproto.h> 5412645Sbde#include <vm/vm.h> 5512662Sdg#include <vm/vm_extern.h> 5612645Sbde 5730354Sphkstatic MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic"); 5863212Sabialstatic MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids"); 5930309Sphk 6012429Sphk/* 6112429Sphk * Locking and stats 6212429Sphk */ 6312429Sphkstatic struct sysctl_lock { 6412429Sphk int sl_lock; 6512429Sphk int sl_want; 6612429Sphk int sl_locked; 6712429Sphk} memlock; 6812429Sphk 6962573Sphkstatic int sysctl_root(SYSCTL_HANDLER_ARGS); 7012429Sphk 7144078Sdfrstruct sysctl_oid_list sysctl__children; /* root list */ 7212152Sphk 7363212Sabialstatic struct sysctl_oid * 7463212Sabialsysctl_find_oidname(const char *name, struct sysctl_oid_list *list) 7563212Sabial{ 7663212Sabial struct sysctl_oid *oidp; 7763212Sabial 7863212Sabial SLIST_FOREACH(oidp, list, oid_link) { 7963212Sabial if (strcmp(oidp->oid_name, name) == 0) { 8063212Sabial return (oidp); 8163212Sabial } 8263212Sabial } 8363212Sabial return (NULL); 8463212Sabial} 8563212Sabial 8612623Sphk/* 8712623Sphk * Initialization of the MIB tree. 8812623Sphk * 8944078Sdfr * Order by number in each list. 9012623Sphk */ 9112429Sphk 9280338Sroamvoid 9380338Sroamsysctl_register_oid(struct sysctl_oid *oidp) 9412152Sphk{ 9544078Sdfr struct sysctl_oid_list *parent = oidp->oid_parent; 9644078Sdfr struct sysctl_oid *p; 9744078Sdfr struct sysctl_oid *q; 9812197Sbde 9944078Sdfr /* 10063212Sabial * First check if another oid with the same name already 10163212Sabial * exists in the parent's list. 10263212Sabial */ 10363212Sabial p = sysctl_find_oidname(oidp->oid_name, parent); 10463212Sabial if (p != NULL) { 10563212Sabial if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 10663212Sabial p->oid_refcnt++; 10763212Sabial return; 10863212Sabial } else { 10963212Sabial printf("can't re-use a leaf (%s)!\n", p->oid_name); 11063212Sabial return; 11163212Sabial } 11263212Sabial } 11363212Sabial /* 11444078Sdfr * If this oid has a number OID_AUTO, give it a number which 11580339Sroam * is greater than any current oid. 11680339Sroam * NOTE: DO NOT change the starting value here, change it in 11780339Sroam * <sys/sysctl.h>, and make sure it is at least 256 to 11880339Sroam * accomodate e.g. net.inet.raw as a static sysctl node. 11944078Sdfr */ 12044078Sdfr if (oidp->oid_number == OID_AUTO) { 12180339Sroam static int newoid = CTL_AUTO_START; 12271510Smckusick 12371510Smckusick oidp->oid_number = newoid++; 12471510Smckusick if (newoid == 0x7fffffff) 12571510Smckusick panic("out of oids"); 12680339Sroam } else if (oidp->oid_number >= CTL_AUTO_START) { 12780339Sroam panic("static sysctl oid too high: %d", oidp->oid_number); 12844078Sdfr } 12944078Sdfr 13044078Sdfr /* 13144078Sdfr * Insert the oid into the parent's list in order. 13244078Sdfr */ 13344078Sdfr q = NULL; 13444078Sdfr SLIST_FOREACH(p, parent, oid_link) { 13544078Sdfr if (oidp->oid_number < p->oid_number) 13644078Sdfr break; 13744078Sdfr q = p; 13844078Sdfr } 13944078Sdfr if (q) 14044078Sdfr SLIST_INSERT_AFTER(q, oidp, oid_link); 14144078Sdfr else 14244078Sdfr SLIST_INSERT_HEAD(parent, oidp, oid_link); 14312152Sphk} 14412131Sphk 14580338Sroamvoid 14680338Sroamsysctl_unregister_oid(struct sysctl_oid *oidp) 14712152Sphk{ 14860938Sjake SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link); 14944078Sdfr} 15012152Sphk 15163212Sabial/* Initialize a new context to keep track of dynamically added sysctls. */ 15263212Sabialint 15363212Sabialsysctl_ctx_init(struct sysctl_ctx_list *c) 15463212Sabial{ 15563212Sabial 15663212Sabial if (c == NULL) { 15763212Sabial return (EINVAL); 15863212Sabial } 15963212Sabial TAILQ_INIT(c); 16063212Sabial return (0); 16163212Sabial} 16263212Sabial 16363212Sabial/* Free the context, and destroy all dynamic oids registered in this context */ 16463212Sabialint 16563212Sabialsysctl_ctx_free(struct sysctl_ctx_list *clist) 16663212Sabial{ 16763212Sabial struct sysctl_ctx_entry *e, *e1; 16863212Sabial int error; 16963212Sabial 17063212Sabial error = 0; 17163212Sabial /* 17263212Sabial * First perform a "dry run" to check if it's ok to remove oids. 17363212Sabial * XXX FIXME 17463212Sabial * XXX This algorithm is a hack. But I don't know any 17563212Sabial * XXX better solution for now... 17663212Sabial */ 17763212Sabial TAILQ_FOREACH(e, clist, link) { 17863212Sabial error = sysctl_remove_oid(e->entry, 0, 0); 17963212Sabial if (error) 18063212Sabial break; 18163212Sabial } 18263212Sabial /* 18363212Sabial * Restore deregistered entries, either from the end, 18463212Sabial * or from the place where error occured. 18563212Sabial * e contains the entry that was not unregistered 18663212Sabial */ 18763212Sabial if (error) 18863212Sabial e1 = TAILQ_PREV(e, sysctl_ctx_list, link); 18963212Sabial else 19063212Sabial e1 = TAILQ_LAST(clist, sysctl_ctx_list); 19163212Sabial while (e1 != NULL) { 19263212Sabial sysctl_register_oid(e1->entry); 19363212Sabial e1 = TAILQ_PREV(e1, sysctl_ctx_list, link); 19463212Sabial } 19563212Sabial if (error) 19663212Sabial return(EBUSY); 19763212Sabial /* Now really delete the entries */ 19863212Sabial e = TAILQ_FIRST(clist); 19963212Sabial while (e != NULL) { 20063212Sabial e1 = TAILQ_NEXT(e, link); 20163212Sabial error = sysctl_remove_oid(e->entry, 1, 0); 20263212Sabial if (error) 20363212Sabial panic("sysctl_remove_oid: corrupt tree, entry: %s", 20463212Sabial e->entry->oid_name); 20563212Sabial free(e, M_SYSCTLOID); 20663212Sabial e = e1; 20763212Sabial } 20863212Sabial return (error); 20963212Sabial} 21063212Sabial 21163212Sabial/* Add an entry to the context */ 21263212Sabialstruct sysctl_ctx_entry * 21363212Sabialsysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) 21463212Sabial{ 21563212Sabial struct sysctl_ctx_entry *e; 21663212Sabial 21763212Sabial if (clist == NULL || oidp == NULL) 21863212Sabial return(NULL); 21963978Speter e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK); 22063212Sabial e->entry = oidp; 22163212Sabial TAILQ_INSERT_HEAD(clist, e, link); 22263212Sabial return (e); 22363212Sabial} 22463212Sabial 22563212Sabial/* Find an entry in the context */ 22663212Sabialstruct sysctl_ctx_entry * 22763212Sabialsysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) 22863212Sabial{ 22963212Sabial struct sysctl_ctx_entry *e; 23063212Sabial 23163212Sabial if (clist == NULL || oidp == NULL) 23263212Sabial return(NULL); 23371999Sphk TAILQ_FOREACH(e, clist, link) { 23463212Sabial if(e->entry == oidp) 23563212Sabial return(e); 23663212Sabial } 23763212Sabial return (e); 23863212Sabial} 23963212Sabial 24044078Sdfr/* 24163212Sabial * Delete an entry from the context. 24263212Sabial * NOTE: this function doesn't free oidp! You have to remove it 24363212Sabial * with sysctl_remove_oid(). 24463212Sabial */ 24563212Sabialint 24663212Sabialsysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) 24763212Sabial{ 24863212Sabial struct sysctl_ctx_entry *e; 24963212Sabial 25063212Sabial if (clist == NULL || oidp == NULL) 25163212Sabial return (EINVAL); 25263212Sabial e = sysctl_ctx_entry_find(clist, oidp); 25363212Sabial if (e != NULL) { 25463212Sabial TAILQ_REMOVE(clist, e, link); 25563212Sabial free(e, M_SYSCTLOID); 25663212Sabial return (0); 25763212Sabial } else 25863212Sabial return (ENOENT); 25963212Sabial} 26063212Sabial 26163212Sabial/* 26263212Sabial * Remove dynamically created sysctl trees. 26363212Sabial * oidp - top of the tree to be removed 26463212Sabial * del - if 0 - just deregister, otherwise free up entries as well 26563212Sabial * recurse - if != 0 traverse the subtree to be deleted 26663212Sabial */ 26763212Sabialint 26863212Sabialsysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse) 26963212Sabial{ 27063212Sabial struct sysctl_oid *p; 27163212Sabial int error; 27263212Sabial 27363212Sabial if (oidp == NULL) 27463212Sabial return(EINVAL); 27563212Sabial if ((oidp->oid_kind & CTLFLAG_DYN) == 0) { 27663212Sabial printf("can't remove non-dynamic nodes!\n"); 27763212Sabial return (EINVAL); 27863212Sabial } 27963212Sabial /* 28063212Sabial * WARNING: normal method to do this should be through 28163212Sabial * sysctl_ctx_free(). Use recursing as the last resort 28263212Sabial * method to purge your sysctl tree of leftovers... 28363212Sabial * However, if some other code still references these nodes, 28463212Sabial * it will panic. 28563212Sabial */ 28663212Sabial if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 28763212Sabial if (oidp->oid_refcnt == 1) { 28863212Sabial SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) { 28963212Sabial if (!recurse) 29063212Sabial return (ENOTEMPTY); 29163212Sabial error = sysctl_remove_oid(p, del, recurse); 29263212Sabial if (error) 29363212Sabial return (error); 29463212Sabial } 29563212Sabial if (del) 29663212Sabial free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID); 29763212Sabial } 29863212Sabial } 29963212Sabial if (oidp->oid_refcnt > 1 ) { 30063212Sabial oidp->oid_refcnt--; 30163212Sabial } else { 30263212Sabial if (oidp->oid_refcnt == 0) { 30363212Sabial printf("Warning: bad oid_refcnt=%u (%s)!\n", 30463212Sabial oidp->oid_refcnt, oidp->oid_name); 30563212Sabial return (EINVAL); 30663212Sabial } 30763212Sabial sysctl_unregister_oid(oidp); 30863212Sabial if (del) { 30963978Speter free((void *)(uintptr_t)(const void *)oidp->oid_name, 31063978Speter M_SYSCTLOID); 31163212Sabial free(oidp, M_SYSCTLOID); 31263212Sabial } 31363212Sabial } 31463212Sabial return (0); 31563212Sabial} 31663212Sabial 31763212Sabial/* 31863212Sabial * Create new sysctls at run time. 31963212Sabial * clist may point to a valid context initialized with sysctl_ctx_init(). 32063212Sabial */ 32163212Sabialstruct sysctl_oid * 32263212Sabialsysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, 32370679Sjhb int number, const char *name, int kind, void *arg1, int arg2, 32470679Sjhb int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr) 32563212Sabial{ 32663212Sabial struct sysctl_oid *oidp; 32763212Sabial ssize_t len; 32863978Speter char *newname; 32963212Sabial 33063212Sabial /* You have to hook up somewhere.. */ 33163212Sabial if (parent == NULL) 33263212Sabial return(NULL); 33363212Sabial /* Check if the node already exists, otherwise create it */ 33463212Sabial oidp = sysctl_find_oidname(name, parent); 33563212Sabial if (oidp != NULL) { 33663212Sabial if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 33763212Sabial oidp->oid_refcnt++; 33863212Sabial /* Update the context */ 33963212Sabial if (clist != NULL) 34063212Sabial sysctl_ctx_entry_add(clist, oidp); 34163212Sabial return (oidp); 34263212Sabial } else { 34363212Sabial printf("can't re-use a leaf (%s)!\n", name); 34463212Sabial return (NULL); 34563212Sabial } 34663212Sabial } 34769781Sdwmalone oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO); 34863212Sabial oidp->oid_parent = parent; 34963212Sabial SLIST_NEXT(oidp, oid_link) = NULL; 35063212Sabial oidp->oid_number = number; 35163212Sabial oidp->oid_refcnt = 1; 35263212Sabial len = strlen(name); 35363978Speter newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK); 35463978Speter bcopy(name, newname, len + 1); 35563978Speter newname[len] = '\0'; 35663978Speter oidp->oid_name = newname; 35763212Sabial oidp->oid_handler = handler; 35863212Sabial oidp->oid_kind = CTLFLAG_DYN | kind; 35963212Sabial if ((kind & CTLTYPE) == CTLTYPE_NODE) { 36063212Sabial /* Allocate space for children */ 36163212Sabial SYSCTL_CHILDREN(oidp) = malloc(sizeof(struct sysctl_oid_list), 36263212Sabial M_SYSCTLOID, M_WAITOK); 36363212Sabial SLIST_INIT(SYSCTL_CHILDREN(oidp)); 36463212Sabial } else { 36563212Sabial oidp->oid_arg1 = arg1; 36663212Sabial oidp->oid_arg2 = arg2; 36763212Sabial } 36863212Sabial oidp->oid_fmt = fmt; 36963212Sabial /* Update the context, if used */ 37063212Sabial if (clist != NULL) 37163212Sabial sysctl_ctx_entry_add(clist, oidp); 37263212Sabial /* Register this oid */ 37363212Sabial sysctl_register_oid(oidp); 37463212Sabial return (oidp); 37563212Sabial} 37663212Sabial 37763212Sabial/* 37844078Sdfr * Register the kernel's oids on startup. 37944078Sdfr */ 38078161SpeterSET_DECLARE(sysctl_set, struct sysctl_oid); 38112152Sphk 38280338Sroamstatic void 38380338Sroamsysctl_register_all(void *arg) 38438869Sbde{ 38578161Speter struct sysctl_oid **oidp; 38678161Speter 38778161Speter SET_FOREACH(oidp, sysctl_set) 38878161Speter sysctl_register_oid(*oidp); 38938869Sbde} 39044078SdfrSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0); 39144078Sdfr 39212623Sphk/* 39312623Sphk * "Staff-functions" 39412623Sphk * 39512650Sphk * These functions implement a presently undocumented interface 39612650Sphk * used by the sysctl program to walk the tree, and get the type 39712650Sphk * so it can print the value. 39812650Sphk * This interface is under work and consideration, and should probably 39912650Sphk * be killed with a big axe by the first person who can find the time. 40012650Sphk * (be aware though, that the proper interface isn't as obvious as it 40112650Sphk * may seem, there are various conflicting requirements. 40212650Sphk * 40312623Sphk * {0,0} printf the entire MIB-tree. 40412623Sphk * {0,1,...} return the name of the "..." OID. 40542467Sphk * {0,2,...} return the next OID. 40612623Sphk * {0,3} return the OID of the name in "new" 40712650Sphk * {0,4,...} return the kind & format info for the "..." OID. 40812623Sphk */ 40912623Sphk 41012152Sphkstatic void 41144078Sdfrsysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i) 41212152Sphk{ 41344078Sdfr int k; 41444078Sdfr struct sysctl_oid *oidp; 41512152Sphk 41644078Sdfr SLIST_FOREACH(oidp, l, oid_link) { 41712152Sphk 41812152Sphk for (k=0; k<i; k++) 41912152Sphk printf(" "); 42012152Sphk 42144078Sdfr printf("%d %s ", oidp->oid_number, oidp->oid_name); 42212152Sphk 42312152Sphk printf("%c%c", 42444078Sdfr oidp->oid_kind & CTLFLAG_RD ? 'R':' ', 42544078Sdfr oidp->oid_kind & CTLFLAG_WR ? 'W':' '); 42612152Sphk 42744078Sdfr if (oidp->oid_handler) 42815241Sphk printf(" *Handler"); 42915241Sphk 43044078Sdfr switch (oidp->oid_kind & CTLTYPE) { 43112243Sphk case CTLTYPE_NODE: 43215241Sphk printf(" Node\n"); 43344078Sdfr if (!oidp->oid_handler) { 43412152Sphk sysctl_sysctl_debug_dump_node( 43544078Sdfr oidp->oid_arg1, i+2); 43612152Sphk } 43712152Sphk break; 43812152Sphk case CTLTYPE_INT: printf(" Int\n"); break; 43912152Sphk case CTLTYPE_STRING: printf(" String\n"); break; 44012152Sphk case CTLTYPE_QUAD: printf(" Quad\n"); break; 44112152Sphk case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 44212152Sphk default: printf("\n"); 44312152Sphk } 44412152Sphk 44512152Sphk } 44612152Sphk} 44712152Sphk 44812152Sphkstatic int 44962573Sphksysctl_sysctl_debug(SYSCTL_HANDLER_ARGS) 45012152Sphk{ 45144078Sdfr sysctl_sysctl_debug_dump_node(&sysctl__children, 0); 45212152Sphk return ENOENT; 45312152Sphk} 45412152Sphk 45512152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 45612623Sphk 0, 0, sysctl_sysctl_debug, "-", ""); 45712152Sphk 45812623Sphkstatic int 45962573Sphksysctl_sysctl_name(SYSCTL_HANDLER_ARGS) 46012623Sphk{ 46112623Sphk int *name = (int *) arg1; 46212623Sphk u_int namelen = arg2; 46344078Sdfr int error = 0; 46444078Sdfr struct sysctl_oid *oid; 46544972Sphk struct sysctl_oid_list *lsp = &sysctl__children, *lsp2; 46612623Sphk char buf[10]; 46712131Sphk 46812623Sphk while (namelen) { 46912623Sphk if (!lsp) { 47041514Sarchie snprintf(buf,sizeof(buf),"%d",*name); 47112623Sphk if (req->oldidx) 47212623Sphk error = SYSCTL_OUT(req, ".", 1); 47312623Sphk if (!error) 47412623Sphk error = SYSCTL_OUT(req, buf, strlen(buf)); 47512623Sphk if (error) 47612623Sphk return (error); 47712623Sphk namelen--; 47812623Sphk name++; 47912623Sphk continue; 48012623Sphk } 48144972Sphk lsp2 = 0; 48244078Sdfr SLIST_FOREACH(oid, lsp, oid_link) { 48344078Sdfr if (oid->oid_number != *name) 48412623Sphk continue; 48512131Sphk 48612623Sphk if (req->oldidx) 48712623Sphk error = SYSCTL_OUT(req, ".", 1); 48812623Sphk if (!error) 48944078Sdfr error = SYSCTL_OUT(req, oid->oid_name, 49044078Sdfr strlen(oid->oid_name)); 49112623Sphk if (error) 49212623Sphk return (error); 49312623Sphk 49412623Sphk namelen--; 49512623Sphk name++; 49612623Sphk 49744972Sphk if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) 49812623Sphk break; 49912623Sphk 50044078Sdfr if (oid->oid_handler) 50112623Sphk break; 50212623Sphk 50344972Sphk lsp2 = (struct sysctl_oid_list *)oid->oid_arg1; 50412623Sphk break; 50512623Sphk } 50644972Sphk lsp = lsp2; 50712623Sphk } 50812623Sphk return (SYSCTL_OUT(req, "", 1)); 50912623Sphk} 51012623Sphk 51112623SphkSYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); 51212623Sphk 51312623Sphkstatic int 51463978Spetersysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, 51544078Sdfr int *next, int *len, int level, struct sysctl_oid **oidpp) 51612623Sphk{ 51744078Sdfr struct sysctl_oid *oidp; 51812623Sphk 51912623Sphk *len = level; 52044078Sdfr SLIST_FOREACH(oidp, lsp, oid_link) { 52144078Sdfr *next = oidp->oid_number; 52244078Sdfr *oidpp = oidp; 52312623Sphk 52412623Sphk if (!namelen) { 52544078Sdfr if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 52612623Sphk return 0; 52744078Sdfr if (oidp->oid_handler) 52812623Sphk /* We really should call the handler here...*/ 52912623Sphk return 0; 53044078Sdfr lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 53163978Speter if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, 53244078Sdfr len, level+1, oidpp)) 53315241Sphk return 0; 53415241Sphk goto next; 53512623Sphk } 53612623Sphk 53744078Sdfr if (oidp->oid_number < *name) 53812623Sphk continue; 53912623Sphk 54044078Sdfr if (oidp->oid_number > *name) { 54144078Sdfr if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 54212623Sphk return 0; 54344078Sdfr if (oidp->oid_handler) 54412623Sphk return 0; 54544078Sdfr lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 54663978Speter if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, 54744078Sdfr next+1, len, level+1, oidpp)) 54812623Sphk return (0); 54915241Sphk goto next; 55012623Sphk } 55144078Sdfr if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 55212623Sphk continue; 55312623Sphk 55444078Sdfr if (oidp->oid_handler) 55512623Sphk continue; 55612623Sphk 55744078Sdfr lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 55863978Speter if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, 55944078Sdfr len, level+1, oidpp)) 56012623Sphk return (0); 56115241Sphk next: 56212623Sphk namelen = 1; 56312623Sphk *len = level; 56412623Sphk } 56512623Sphk return 1; 56612623Sphk} 56712623Sphk 56812623Sphkstatic int 56962573Sphksysctl_sysctl_next(SYSCTL_HANDLER_ARGS) 57012623Sphk{ 57112623Sphk int *name = (int *) arg1; 57212623Sphk u_int namelen = arg2; 57312623Sphk int i, j, error; 57412623Sphk struct sysctl_oid *oid; 57544078Sdfr struct sysctl_oid_list *lsp = &sysctl__children; 57612623Sphk int newoid[CTL_MAXNAME]; 57712623Sphk 57863978Speter i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid); 57912623Sphk if (i) 58012623Sphk return ENOENT; 58112650Sphk error = SYSCTL_OUT(req, newoid, j * sizeof (int)); 58212623Sphk return (error); 58312623Sphk} 58412623Sphk 58512623SphkSYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, ""); 58612623Sphk 58712623Sphkstatic int 58844078Sdfrname2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp) 58912623Sphk{ 59044078Sdfr int i; 59144078Sdfr struct sysctl_oid *oidp; 59244078Sdfr struct sysctl_oid_list *lsp = &sysctl__children; 59312623Sphk char *p; 59412623Sphk 59512623Sphk if (!*name) 59612623Sphk return ENOENT; 59712623Sphk 59812623Sphk p = name + strlen(name) - 1 ; 59912623Sphk if (*p == '.') 60012623Sphk *p = '\0'; 60112623Sphk 60212623Sphk *len = 0; 60312623Sphk 60412623Sphk for (p = name; *p && *p != '.'; p++) 60512623Sphk ; 60612623Sphk i = *p; 60712623Sphk if (i == '.') 60812623Sphk *p = '\0'; 60912623Sphk 61044078Sdfr oidp = SLIST_FIRST(lsp); 61112623Sphk 61244078Sdfr while (oidp && *len < CTL_MAXNAME) { 61344078Sdfr if (strcmp(name, oidp->oid_name)) { 61444078Sdfr oidp = SLIST_NEXT(oidp, oid_link); 61512623Sphk continue; 61612623Sphk } 61744078Sdfr *oid++ = oidp->oid_number; 61812623Sphk (*len)++; 61912623Sphk 62012623Sphk if (!i) { 62144078Sdfr if (oidpp) 62244078Sdfr *oidpp = oidp; 62312623Sphk return (0); 62412623Sphk } 62512623Sphk 62644078Sdfr if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 62712623Sphk break; 62812623Sphk 62944078Sdfr if (oidp->oid_handler) 63012623Sphk break; 63112623Sphk 63244078Sdfr lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 63344078Sdfr oidp = SLIST_FIRST(lsp); 63412623Sphk name = p+1; 63512623Sphk for (p = name; *p && *p != '.'; p++) 63612623Sphk ; 63712623Sphk i = *p; 63812623Sphk if (i == '.') 63912623Sphk *p = '\0'; 64012623Sphk } 64112623Sphk return ENOENT; 64212623Sphk} 64312623Sphk 64412623Sphkstatic int 64562573Sphksysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS) 64612623Sphk{ 64712623Sphk char *p; 64812623Sphk int error, oid[CTL_MAXNAME], len; 64912623Sphk struct sysctl_oid *op = 0; 65012623Sphk 65112623Sphk if (!req->newlen) 65212623Sphk return ENOENT; 65345140Sphk if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */ 65445140Sphk return (ENAMETOOLONG); 65512623Sphk 65612623Sphk p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK); 65712623Sphk 65812623Sphk error = SYSCTL_IN(req, p, req->newlen); 65912623Sphk if (error) { 66012623Sphk free(p, M_SYSCTL); 66112623Sphk return (error); 66212623Sphk } 66312623Sphk 66412623Sphk p [req->newlen] = '\0'; 66512623Sphk 66612623Sphk error = name2oid(p, oid, &len, &op); 66712623Sphk 66812623Sphk free(p, M_SYSCTL); 66912623Sphk 67012623Sphk if (error) 67112623Sphk return (error); 67212623Sphk 67312650Sphk error = SYSCTL_OUT(req, oid, len * sizeof *oid); 67412623Sphk return (error); 67512623Sphk} 67612623Sphk 67712910SphkSYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 67812623Sphk sysctl_sysctl_name2oid, "I", ""); 67912623Sphk 68012623Sphkstatic int 68162573Sphksysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS) 68212623Sphk{ 68344078Sdfr struct sysctl_oid *oid; 68453977Sgreen int error; 68512623Sphk 68653977Sgreen error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); 68753977Sgreen if (error) 68853977Sgreen return (error); 68912623Sphk 69044078Sdfr if (!oid->oid_fmt) 69153977Sgreen return (ENOENT); 69253977Sgreen error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind)); 69353977Sgreen if (error) 69453977Sgreen return (error); 69553977Sgreen error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1); 69612650Sphk return (error); 69712623Sphk} 69812623Sphk 69942467Sphk 70012623SphkSYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, ""); 70112623Sphk 70212243Sphk/* 70312623Sphk * Default "handler" functions. 70412623Sphk */ 70512623Sphk 70612623Sphk/* 70742095Sdfr * Handle an int, signed or unsigned. 70812243Sphk * Two cases: 70912243Sphk * a variable: point arg1 at it. 71012243Sphk * a constant: pass it in arg2. 71112243Sphk */ 71212243Sphk 71311865Sphkint 71462573Sphksysctl_handle_int(SYSCTL_HANDLER_ARGS) 71511863Sphk{ 71612243Sphk int error = 0; 71711863Sphk 71812243Sphk if (arg1) 71912243Sphk error = SYSCTL_OUT(req, arg1, sizeof(int)); 72020506Sbde else 72112243Sphk error = SYSCTL_OUT(req, &arg2, sizeof(int)); 72211863Sphk 72312243Sphk if (error || !req->newptr) 72412243Sphk return (error); 72511863Sphk 72612243Sphk if (!arg1) 72712243Sphk error = EPERM; 72812243Sphk else 72912243Sphk error = SYSCTL_IN(req, arg1, sizeof(int)); 73012243Sphk return (error); 73111863Sphk} 73211863Sphk 73312243Sphk/* 73445140Sphk * Handle a long, signed or unsigned. arg1 points to it. 73538517Sdfr */ 73638517Sdfr 73738517Sdfrint 73862573Sphksysctl_handle_long(SYSCTL_HANDLER_ARGS) 73938517Sdfr{ 74038517Sdfr int error = 0; 74138517Sdfr 74245140Sphk if (!arg1) 74345140Sphk return (EINVAL); 74442095Sdfr error = SYSCTL_OUT(req, arg1, sizeof(long)); 74538517Sdfr 74638517Sdfr if (error || !req->newptr) 74738517Sdfr return (error); 74838517Sdfr 74945140Sphk error = SYSCTL_IN(req, arg1, sizeof(long)); 75038517Sdfr return (error); 75138517Sdfr} 75238517Sdfr 75338517Sdfr/* 75412243Sphk * Handle our generic '\0' terminated 'C' string. 75512243Sphk * Two cases: 75612243Sphk * a variable string: point arg1 at it, arg2 is max length. 75712243Sphk * a constant string: point arg1 at it, arg2 is zero. 75812243Sphk */ 75912243Sphk 76011865Sphkint 76162573Sphksysctl_handle_string(SYSCTL_HANDLER_ARGS) 76211863Sphk{ 76312243Sphk int error=0; 76411863Sphk 76512297Sphk error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1); 76611863Sphk 76745140Sphk if (error || !req->newptr) 76812243Sphk return (error); 76911863Sphk 77045140Sphk if ((req->newlen - req->newidx) >= arg2) { 77145140Sphk error = EINVAL; 77212243Sphk } else { 77312243Sphk arg2 = (req->newlen - req->newidx); 77412243Sphk error = SYSCTL_IN(req, arg1, arg2); 77512243Sphk ((char *)arg1)[arg2] = '\0'; 77611863Sphk } 77712131Sphk 77812131Sphk return (error); 77911863Sphk} 78011863Sphk 78112243Sphk/* 78212243Sphk * Handle any kind of opaque data. 78312243Sphk * arg1 points to it, arg2 is the size. 78412243Sphk */ 78512243Sphk 78611865Sphkint 78762573Sphksysctl_handle_opaque(SYSCTL_HANDLER_ARGS) 78811863Sphk{ 78912243Sphk int error; 79012243Sphk 79112243Sphk error = SYSCTL_OUT(req, arg1, arg2); 79212243Sphk 79312243Sphk if (error || !req->newptr) 79412243Sphk return (error); 79512243Sphk 79612243Sphk error = SYSCTL_IN(req, arg1, arg2); 79712243Sphk 79812243Sphk return (error); 79912243Sphk} 80012243Sphk 80112260Sphk/* 80212260Sphk * Transfer functions to/from kernel space. 80312260Sphk * XXX: rather untested at this point 80412260Sphk */ 80512260Sphkstatic int 80638517Sdfrsysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) 80712243Sphk{ 80838517Sdfr size_t i = 0; 80912260Sphk 81012260Sphk if (req->oldptr) { 81138517Sdfr i = l; 81273971Stmm if (req->oldlen <= req->oldidx) 81373971Stmm i = 0; 81473971Stmm else 81573971Stmm if (i > req->oldlen - req->oldidx) 81673971Stmm i = req->oldlen - req->oldidx; 81712260Sphk if (i > 0) 81817971Sbde bcopy(p, (char *)req->oldptr + req->oldidx, i); 81912243Sphk } 82012260Sphk req->oldidx += l; 82116282Snate if (req->oldptr && i != l) 82211863Sphk return (ENOMEM); 82312260Sphk return (0); 82412243Sphk} 82512243Sphk 82612260Sphkstatic int 82738517Sdfrsysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) 82812243Sphk{ 82912260Sphk if (!req->newptr) 83012260Sphk return 0; 83112260Sphk if (req->newlen - req->newidx < l) 83211863Sphk return (EINVAL); 83317971Sbde bcopy((char *)req->newptr + req->newidx, p, l); 83412243Sphk req->newidx += l; 83512131Sphk return (0); 83611863Sphk} 83711863Sphk 83816282Snateint 83983366Sjuliankernel_sysctl(struct thread *td, int *name, u_int namelen, void *old, 84076834Sjlemon size_t *oldlenp, void *new, size_t newlen, size_t *retval) 84116282Snate{ 84216282Snate int error = 0; 84316282Snate struct sysctl_req req; 84416282Snate 84516282Snate bzero(&req, sizeof req); 84616282Snate 84783366Sjulian req.p = td->td_proc; 84816282Snate 84916282Snate if (oldlenp) { 85016282Snate req.oldlen = *oldlenp; 85116282Snate } 85216282Snate 85316282Snate if (old) { 85416282Snate req.oldptr= old; 85516282Snate } 85616282Snate 85777646Sdd if (new != NULL) { 85816282Snate req.newlen = newlen; 85916282Snate req.newptr = new; 86016282Snate } 86116282Snate 86216282Snate req.oldfunc = sysctl_old_kernel; 86316282Snate req.newfunc = sysctl_new_kernel; 86416282Snate req.lock = 1; 86516282Snate 86616282Snate /* XXX this should probably be done in a general way */ 86716282Snate while (memlock.sl_lock) { 86816282Snate memlock.sl_want = 1; 86916282Snate (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 87016282Snate memlock.sl_locked++; 87116282Snate } 87216282Snate memlock.sl_lock = 1; 87316282Snate 87416282Snate error = sysctl_root(0, name, namelen, &req); 87516282Snate 87616282Snate if (req.lock == 2) 87757975Sphk vsunlock(req.oldptr, req.oldlen); 87816282Snate 87916282Snate memlock.sl_lock = 0; 88016282Snate 88116282Snate if (memlock.sl_want) { 88216282Snate memlock.sl_want = 0; 88316282Snate wakeup((caddr_t)&memlock); 88416282Snate } 88516282Snate 88616282Snate if (error && error != ENOMEM) 88716282Snate return (error); 88816282Snate 88916282Snate if (retval) { 89016282Snate if (req.oldptr && req.oldidx > req.oldlen) 89116282Snate *retval = req.oldlen; 89216282Snate else 89316282Snate *retval = req.oldidx; 89416282Snate } 89516282Snate return (error); 89616282Snate} 89716282Snate 89876834Sjlemonint 89983366Sjuliankernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp, 90076834Sjlemon void *new, size_t newlen, size_t *retval) 90176834Sjlemon{ 90276834Sjlemon int oid[CTL_MAXNAME]; 90378620Smjacob size_t oidlen, plen; 90478620Smjacob int error; 90576834Sjlemon 90676834Sjlemon oid[0] = 0; /* sysctl internal magic */ 90776834Sjlemon oid[1] = 3; /* name2oid */ 90876834Sjlemon oidlen = sizeof(oid); 90976834Sjlemon 91083366Sjulian error = kernel_sysctl(td, oid, 2, oid, &oidlen, 91176834Sjlemon (void *)name, strlen(name), &plen); 91276834Sjlemon if (error) 91376834Sjlemon return (error); 91476834Sjlemon 91583366Sjulian error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp, 91676834Sjlemon new, newlen, retval); 91776834Sjlemon return (error); 91876834Sjlemon} 91976834Sjlemon 92012260Sphk/* 92112260Sphk * Transfer function to/from user space. 92212260Sphk */ 92312260Sphkstatic int 92438517Sdfrsysctl_old_user(struct sysctl_req *req, const void *p, size_t l) 92512243Sphk{ 92638517Sdfr int error = 0; 92738517Sdfr size_t i = 0; 92812243Sphk 92912429Sphk if (req->lock == 1 && req->oldptr) { 93012429Sphk vslock(req->oldptr, req->oldlen); 93112429Sphk req->lock = 2; 93212429Sphk } 93312260Sphk if (req->oldptr) { 93438517Sdfr i = l; 93573971Stmm if (req->oldlen <= req->oldidx) 93673971Stmm i = 0; 93773971Stmm else 93873971Stmm if (i > req->oldlen - req->oldidx) 93973971Stmm i = req->oldlen - req->oldidx; 94012260Sphk if (i > 0) 94117971Sbde error = copyout(p, (char *)req->oldptr + req->oldidx, 94217971Sbde i); 94312260Sphk } 94412260Sphk req->oldidx += l; 94512243Sphk if (error) 94612243Sphk return (error); 94712260Sphk if (req->oldptr && i < l) 94812243Sphk return (ENOMEM); 94912260Sphk return (0); 95012243Sphk} 95112243Sphk 95212260Sphkstatic int 95338517Sdfrsysctl_new_user(struct sysctl_req *req, void *p, size_t l) 95412243Sphk{ 95512285Sphk int error; 95612260Sphk 95712260Sphk if (!req->newptr) 95812260Sphk return 0; 95912260Sphk if (req->newlen - req->newidx < l) 96012243Sphk return (EINVAL); 96117971Sbde error = copyin((char *)req->newptr + req->newidx, p, l); 96212243Sphk req->newidx += l; 96312243Sphk return (error); 96412243Sphk} 96512243Sphk 9661541Srgrimesint 96753977Sgreensysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid, 96853977Sgreen int *nindx, struct sysctl_req *req) 96912131Sphk{ 97044078Sdfr struct sysctl_oid *oid; 97153977Sgreen int indx; 97212131Sphk 97353977Sgreen oid = SLIST_FIRST(&sysctl__children); 97412131Sphk indx = 0; 97544078Sdfr while (oid && indx < CTL_MAXNAME) { 97644078Sdfr if (oid->oid_number == name[indx]) { 97712131Sphk indx++; 97844078Sdfr if (oid->oid_kind & CTLFLAG_NOLOCK) 97912429Sphk req->lock = 0; 98044078Sdfr if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 98153977Sgreen if (oid->oid_handler != NULL || 98253977Sgreen indx == namelen) { 98353977Sgreen *noid = oid; 98453977Sgreen if (nindx != NULL) 98553977Sgreen *nindx = indx; 98653977Sgreen return (0); 98753977Sgreen } 98853977Sgreen oid = SLIST_FIRST( 98953977Sgreen (struct sysctl_oid_list *)oid->oid_arg1); 99053977Sgreen } else if (indx == namelen) { 99153977Sgreen *noid = oid; 99253977Sgreen if (nindx != NULL) 99353977Sgreen *nindx = indx; 99453977Sgreen return (0); 99512131Sphk } else { 99653977Sgreen return (ENOTDIR); 99712131Sphk } 99812131Sphk } else { 99944078Sdfr oid = SLIST_NEXT(oid, oid_link); 100012131Sphk } 100112131Sphk } 100253977Sgreen return (ENOENT); 100353977Sgreen} 100453977Sgreen 100553977Sgreen/* 100653977Sgreen * Traverse our tree, and find the right node, execute whatever it points 100753977Sgreen * to, and return the resulting error code. 100853977Sgreen */ 100953977Sgreen 101053977Sgreenint 101162573Sphksysctl_root(SYSCTL_HANDLER_ARGS) 101253977Sgreen{ 101353977Sgreen struct sysctl_oid *oid; 101453977Sgreen int error, indx; 101553977Sgreen 101653977Sgreen error = sysctl_find_oid(arg1, arg2, &oid, &indx, req); 101753977Sgreen if (error) 101853977Sgreen return (error); 101953977Sgreen 102053977Sgreen if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 102153977Sgreen /* 102253977Sgreen * You can't call a sysctl when it's a node, but has 102353977Sgreen * no handler. Inform the user that it's a node. 102453977Sgreen * The indx may or may not be the same as namelen. 102553977Sgreen */ 102653977Sgreen if (oid->oid_handler == NULL) 102753977Sgreen return (EISDIR); 102853977Sgreen } 102953977Sgreen 103083968Srwatson /* Is this sysctl writable? */ 103183968Srwatson if (req->newptr && !(oid->oid_kind & CTLFLAG_WR)) 103212131Sphk return (EPERM); 103312131Sphk 103483968Srwatson /* Is this sysctl sensitive to securelevels? */ 103583968Srwatson if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) { 103683968Srwatson if (req->p == NULL) { 103783968Srwatson error = securelevel_gt(NULL, 0); /* XXX */ 103883968Srwatson if (error) 103983968Srwatson return (error); 104083968Srwatson } else { 104183968Srwatson error = securelevel_gt(req->p->p_ucred, 0); 104283968Srwatson if (error) 104383968Srwatson return (error); 104483968Srwatson } 104583968Srwatson } 104612910Sphk 104783968Srwatson /* Is this sysctl writable by only privileged users? */ 104883968Srwatson if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) { 104983968Srwatson if (req->p != NULL) { 105083968Srwatson int flags; 105183968Srwatson 105283968Srwatson if (oid->oid_kind & CTLFLAG_PRISON) 105383968Srwatson flags = PRISON_ROOT; 105483968Srwatson else 105583968Srwatson flags = 0; 105683968Srwatson error = suser_xxx(NULL, req->p, flags); 105783968Srwatson if (error) 105883968Srwatson return (error); 105983968Srwatson } 106083968Srwatson } 106183968Srwatson 106244078Sdfr if (!oid->oid_handler) 106312131Sphk return EINVAL; 106412131Sphk 106553977Sgreen if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) 106653977Sgreen error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx, 106753977Sgreen req); 106853977Sgreen else 106953977Sgreen error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2, 107053977Sgreen req); 107153977Sgreen return (error); 107212131Sphk} 107312131Sphk 107412221Sbde#ifndef _SYS_SYSPROTO_H_ 107512171Sphkstruct sysctl_args { 107612171Sphk int *name; 107712171Sphk u_int namelen; 107812171Sphk void *old; 107912171Sphk size_t *oldlenp; 108012171Sphk void *new; 108112171Sphk size_t newlen; 108212171Sphk}; 108312221Sbde#endif 108412171Sphk 108582746Sdillon/* 108682746Sdillon * MPSAFE 108782746Sdillon */ 108812131Sphkint 108983366Sjulian__sysctl(struct thread *td, struct sysctl_args *uap) 10901541Srgrimes{ 109182746Sdillon int error, name[CTL_MAXNAME]; 109238517Sdfr size_t j; 10931541Srgrimes 10941541Srgrimes if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 10951541Srgrimes return (EINVAL); 109611863Sphk 10973308Sphk error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 10983308Sphk if (error) 10991541Srgrimes return (error); 11001541Srgrimes 110182746Sdillon mtx_lock(&Giant); 110282746Sdillon 110383366Sjulian error = userland_sysctl(td, name, uap->namelen, 110412171Sphk uap->old, uap->oldlenp, 0, 110512260Sphk uap->new, uap->newlen, &j); 110612260Sphk if (error && error != ENOMEM) 110782746Sdillon goto done2; 110812260Sphk if (uap->oldlenp) { 110982746Sdillon int i = copyout(&j, uap->oldlenp, sizeof(j)); 111012260Sphk if (i) 111182746Sdillon error = i; 111212260Sphk } 111382746Sdillondone2: 111482746Sdillon mtx_unlock(&Giant); 111512260Sphk return (error); 111612171Sphk} 111712171Sphk 111812171Sphk/* 111912171Sphk * This is used from various compatibility syscalls too. That's why name 112012171Sphk * must be in kernel space. 112112171Sphk */ 112212171Sphkint 112383366Sjulianuserland_sysctl(struct thread *td, int *name, u_int namelen, void *old, 112480338Sroam size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval) 112512171Sphk{ 112612429Sphk int error = 0; 112716159Sphk struct sysctl_req req, req2; 112812171Sphk 112912243Sphk bzero(&req, sizeof req); 113012243Sphk 113183366Sjulian req.p = td->td_proc; 113212285Sphk 113312171Sphk if (oldlenp) { 113412171Sphk if (inkernel) { 113512243Sphk req.oldlen = *oldlenp; 113612171Sphk } else { 113712260Sphk error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); 113812171Sphk if (error) 113912171Sphk return (error); 114012171Sphk } 114112171Sphk } 114212171Sphk 114312243Sphk if (old) { 114452644Sphk if (!useracc(old, req.oldlen, VM_PROT_WRITE)) 114512243Sphk return (EFAULT); 114612243Sphk req.oldptr= old; 114712243Sphk } 114812131Sphk 114977646Sdd if (new != NULL) { 115052644Sphk if (!useracc(new, req.newlen, VM_PROT_READ)) 115112243Sphk return (EFAULT); 115212243Sphk req.newlen = newlen; 115312243Sphk req.newptr = new; 115411863Sphk } 115512131Sphk 115612243Sphk req.oldfunc = sysctl_old_user; 115712243Sphk req.newfunc = sysctl_new_user; 115812429Sphk req.lock = 1; 115911863Sphk 116012429Sphk /* XXX this should probably be done in a general way */ 116112429Sphk while (memlock.sl_lock) { 116212429Sphk memlock.sl_want = 1; 116312429Sphk (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 116412429Sphk memlock.sl_locked++; 116512429Sphk } 116612429Sphk memlock.sl_lock = 1; 116712429Sphk 116816159Sphk do { 116916159Sphk req2 = req; 117016159Sphk error = sysctl_root(0, name, namelen, &req2); 117116159Sphk } while (error == EAGAIN); 117212243Sphk 117316159Sphk req = req2; 117412429Sphk if (req.lock == 2) 117557975Sphk vsunlock(req.oldptr, req.oldlen); 117612429Sphk 117712429Sphk memlock.sl_lock = 0; 117812429Sphk 117912429Sphk if (memlock.sl_want) { 118012429Sphk memlock.sl_want = 0; 118112429Sphk wakeup((caddr_t)&memlock); 118212429Sphk } 118312429Sphk 118412260Sphk if (error && error != ENOMEM) 118512260Sphk return (error); 118612260Sphk 118712260Sphk if (retval) { 118812260Sphk if (req.oldptr && req.oldidx > req.oldlen) 118912243Sphk *retval = req.oldlen; 119012260Sphk else 119112260Sphk *retval = req.oldidx; 119211863Sphk } 119312260Sphk return (error); 11941541Srgrimes} 11951541Srgrimes 11961541Srgrimes#ifdef COMPAT_43 11971541Srgrimes#include <sys/socket.h> 119815103Sphk#include <vm/vm_param.h> 119915103Sphk 12001541Srgrimes#define KINFO_PROC (0<<8) 12011541Srgrimes#define KINFO_RT (1<<8) 12021541Srgrimes#define KINFO_VNODE (2<<8) 12031541Srgrimes#define KINFO_FILE (3<<8) 12041541Srgrimes#define KINFO_METER (4<<8) 12051541Srgrimes#define KINFO_LOADAVG (5<<8) 12061541Srgrimes#define KINFO_CLOCKRATE (6<<8) 12071541Srgrimes 12089455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 12099455Speter#define KINFO_BSDI_SYSINFO (101<<8) 12109455Speter 12119455Speter/* 12129455Speter * XXX this is bloat, but I hope it's better here than on the potentially 12139455Speter * limited kernel stack... -Peter 12149455Speter */ 12159455Speter 121612819Sphkstatic struct { 12179455Speter int bsdi_machine; /* "i386" on BSD/386 */ 12189455Speter/* ^^^ this is an offset to the string, relative to the struct start */ 12199455Speter char *pad0; 12209455Speter long pad1; 12219455Speter long pad2; 12229455Speter long pad3; 12239455Speter u_long pad4; 12249455Speter u_long pad5; 12259455Speter u_long pad6; 12269455Speter 12279455Speter int bsdi_ostype; /* "BSD/386" on BSD/386 */ 12289455Speter int bsdi_osrelease; /* "1.1" on BSD/386 */ 12299455Speter long pad7; 12309455Speter long pad8; 12319455Speter char *pad9; 12329455Speter 12339455Speter long pad10; 12349455Speter long pad11; 12359455Speter int pad12; 12369455Speter long pad13; 12379455Speter quad_t pad14; 12389455Speter long pad15; 12399455Speter 12409455Speter struct timeval pad16; 12419455Speter /* we dont set this, because BSDI's uname used gethostname() instead */ 12429455Speter int bsdi_hostname; /* hostname on BSD/386 */ 12439455Speter 12449455Speter /* the actual string data is appended here */ 12459455Speter 12469455Speter} bsdi_si; 12479455Speter/* 12489455Speter * this data is appended to the end of the bsdi_si structure during copyout. 12499455Speter * The "char *" offsets are relative to the base of the bsdi_si struct. 12509455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 12519455Speter * should not exceed the length of the buffer here... (or else!! :-) 12529455Speter */ 125312819Sphkstatic char bsdi_strings[80]; /* It had better be less than this! */ 12549455Speter 125512221Sbde#ifndef _SYS_SYSPROTO_H_ 12561541Srgrimesstruct getkerninfo_args { 12571541Srgrimes int op; 12581541Srgrimes char *where; 125938864Sbde size_t *size; 12601541Srgrimes int arg; 12611541Srgrimes}; 126212221Sbde#endif 12631541Srgrimes 126482746Sdillon/* 126582746Sdillon * MPSAFE 126682746Sdillon */ 12671549Srgrimesint 126883366Sjulianogetkerninfo(struct thread *td, struct getkerninfo_args *uap) 12691541Srgrimes{ 127012171Sphk int error, name[6]; 127138517Sdfr size_t size; 127282494Speter u_int needed = 0; 12731541Srgrimes 127482746Sdillon mtx_lock(&Giant); 127582746Sdillon 12761541Srgrimes switch (uap->op & 0xff00) { 12771541Srgrimes 12781541Srgrimes case KINFO_RT: 127912171Sphk name[0] = CTL_NET; 128012171Sphk name[1] = PF_ROUTE; 128112171Sphk name[2] = 0; 128212171Sphk name[3] = (uap->op & 0xff0000) >> 16; 128312171Sphk name[4] = uap->op & 0xff; 128412171Sphk name[5] = uap->arg; 128583366Sjulian error = userland_sysctl(td, name, 6, uap->where, uap->size, 128612429Sphk 0, 0, 0, &size); 12871541Srgrimes break; 12881541Srgrimes 12891541Srgrimes case KINFO_VNODE: 129012171Sphk name[0] = CTL_KERN; 129112171Sphk name[1] = KERN_VNODE; 129283366Sjulian error = userland_sysctl(td, name, 2, uap->where, uap->size, 129312429Sphk 0, 0, 0, &size); 12941541Srgrimes break; 12951541Srgrimes 12961541Srgrimes case KINFO_PROC: 129712171Sphk name[0] = CTL_KERN; 129812171Sphk name[1] = KERN_PROC; 129912171Sphk name[2] = uap->op & 0xff; 130012171Sphk name[3] = uap->arg; 130183366Sjulian error = userland_sysctl(td, name, 4, uap->where, uap->size, 130212429Sphk 0, 0, 0, &size); 13031541Srgrimes break; 13041541Srgrimes 13051541Srgrimes case KINFO_FILE: 130612171Sphk name[0] = CTL_KERN; 130712171Sphk name[1] = KERN_FILE; 130883366Sjulian error = userland_sysctl(td, name, 2, uap->where, uap->size, 130912429Sphk 0, 0, 0, &size); 13101541Srgrimes break; 13111541Srgrimes 13121541Srgrimes case KINFO_METER: 131312171Sphk name[0] = CTL_VM; 131412171Sphk name[1] = VM_METER; 131583366Sjulian error = userland_sysctl(td, name, 2, uap->where, uap->size, 131612429Sphk 0, 0, 0, &size); 13171541Srgrimes break; 13181541Srgrimes 13191541Srgrimes case KINFO_LOADAVG: 132012171Sphk name[0] = CTL_VM; 132112171Sphk name[1] = VM_LOADAVG; 132283366Sjulian error = userland_sysctl(td, name, 2, uap->where, uap->size, 132312429Sphk 0, 0, 0, &size); 13241541Srgrimes break; 13251541Srgrimes 13261541Srgrimes case KINFO_CLOCKRATE: 132712171Sphk name[0] = CTL_KERN; 132812171Sphk name[1] = KERN_CLOCKRATE; 132983366Sjulian error = userland_sysctl(td, name, 2, uap->where, uap->size, 133012429Sphk 0, 0, 0, &size); 13311541Srgrimes break; 13321541Srgrimes 13339455Speter case KINFO_BSDI_SYSINFO: { 13349455Speter /* 13359455Speter * this is pretty crude, but it's just enough for uname() 13369455Speter * from BSDI's 1.x libc to work. 13379455Speter * 133882494Speter * *size gives the size of the buffer before the call, and 133982494Speter * the amount of data copied after a successful call. 134082494Speter * If successful, the return value is the amount of data 134182494Speter * available, which can be larger than *size. 134282494Speter * 134382494Speter * BSDI's 2.x product apparently fails with ENOMEM if *size 134482494Speter * is too small. 13459455Speter */ 13469455Speter 13479455Speter u_int left; 13489455Speter char *s; 13499455Speter 13509455Speter bzero((char *)&bsdi_si, sizeof(bsdi_si)); 13519455Speter bzero(bsdi_strings, sizeof(bsdi_strings)); 13529455Speter 13539455Speter s = bsdi_strings; 13549455Speter 13559455Speter bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 13569455Speter strcpy(s, ostype); 13579455Speter s += strlen(s) + 1; 13589455Speter 13599455Speter bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 13609455Speter strcpy(s, osrelease); 13619455Speter s += strlen(s) + 1; 13629455Speter 13639455Speter bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 13649455Speter strcpy(s, machine); 13659455Speter s += strlen(s) + 1; 13669455Speter 13679455Speter needed = sizeof(bsdi_si) + (s - bsdi_strings); 13689455Speter 136982494Speter if ((uap->where == NULL) || (uap->size == NULL)) { 13709455Speter /* process is asking how much buffer to supply.. */ 13719455Speter size = needed; 13729455Speter error = 0; 13739455Speter break; 13749455Speter } 13759455Speter 137682494Speter if ((error = copyin(uap->size, &size, sizeof(size))) != 0) 137782494Speter break; 13789455Speter 13799455Speter /* if too much buffer supplied, trim it down */ 13809455Speter if (size > needed) 13819455Speter size = needed; 13829455Speter 13839455Speter /* how much of the buffer is remaining */ 13849455Speter left = size; 13859455Speter 13869455Speter if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 13879455Speter break; 13889455Speter 13899455Speter /* is there any point in continuing? */ 13909455Speter if (left > sizeof(bsdi_si)) { 13919455Speter left -= sizeof(bsdi_si); 13929455Speter error = copyout(&bsdi_strings, 13939455Speter uap->where + sizeof(bsdi_si), left); 13949455Speter } 13959455Speter break; 13969455Speter } 13979455Speter 13981541Srgrimes default: 139982746Sdillon error = EOPNOTSUPP; 140082746Sdillon break; 14011541Srgrimes } 140282746Sdillon if (error == 0) { 140383366Sjulian td->td_retval[0] = needed ? needed : size; 140482746Sdillon if (uap->size) { 140582746Sdillon error = copyout((caddr_t)&size, (caddr_t)uap->size, 140682746Sdillon sizeof(size)); 140782746Sdillon } 140882746Sdillon } 140982746Sdillon mtx_unlock(&Giant); 14101541Srgrimes return (error); 14111541Srgrimes} 14121541Srgrimes#endif /* COMPAT_43 */ 1413