kern_sysctl.c revision 15103
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 4015103Sphk * $Id: kern_sysctl.c,v 1.60 1996/03/11 02:18:22 hsu Exp $ 411541Srgrimes */ 421541Srgrimes 431541Srgrimes#include <sys/param.h> 441541Srgrimes#include <sys/kernel.h> 451541Srgrimes#include <sys/sysctl.h> 4612623Sphk#include <sys/malloc.h> 4712662Sdg#include <sys/proc.h> 4815103Sphk#include <sys/systm.h> 4915103Sphk#include <sys/sysproto.h> 5012645Sbde#include <vm/vm.h> 5112662Sdg#include <vm/vm_extern.h> 5215103Sphk#include <sys/vnode.h> 5312645Sbde 5412429Sphk/* 5512429Sphk * Locking and stats 5612429Sphk */ 5712429Sphkstatic struct sysctl_lock { 5812429Sphk int sl_lock; 5912429Sphk int sl_want; 6012429Sphk int sl_locked; 6112429Sphk} memlock; 6212429Sphk 6312429Sphkstatic int sysctl_root SYSCTL_HANDLER_ARGS; 6412429Sphk 6512152Sphkextern struct linker_set sysctl_; 6612152Sphk 6712623Sphk/* 6812623Sphk * Initialization of the MIB tree. 6912623Sphk * 7012623Sphk * Order by number in each linker_set. 7112623Sphk */ 7212429Sphk 7312429Sphkstatic int 7412197Sbdesysctl_order_cmp(const void *a, const void *b) 7512152Sphk{ 7612197Sbde const struct sysctl_oid **pa, **pb; 7712197Sbde 7812197Sbde pa = (const struct sysctl_oid **)a; 7912197Sbde pb = (const struct sysctl_oid **)b; 8012197Sbde if (*pa == NULL) 8112197Sbde return (1); 8212197Sbde if (*pb == NULL) 8312197Sbde return (-1); 8412152Sphk return ((*pa)->oid_number - (*pb)->oid_number); 8512152Sphk} 8612131Sphk 8712152Sphkstatic void 8812152Sphksysctl_order(void *arg) 8912152Sphk{ 9012623Sphk int j, k; 9112152Sphk struct linker_set *l = (struct linker_set *) arg; 9212152Sphk struct sysctl_oid **oidpp; 9312152Sphk 9412623Sphk /* First, find the highest oid we have */ 9512152Sphk j = l->ls_length; 9612152Sphk oidpp = (struct sysctl_oid **) l->ls_items; 9712623Sphk for (k = 0; j--; oidpp++) 9812623Sphk if (*oidpp && (*oidpp)->oid_number > k) 9912623Sphk k = (*oidpp)->oid_number; 10012623Sphk 10112623Sphk /* Next, replace all OID_AUTO oids with new numbers */ 10212623Sphk j = l->ls_length; 10312623Sphk oidpp = (struct sysctl_oid **) l->ls_items; 10412623Sphk k += 100; 10512623Sphk for (; j--; oidpp++) 10612623Sphk if (*oidpp && (*oidpp)->oid_number == OID_AUTO) 10712623Sphk (*oidpp)->oid_number = k++; 10812623Sphk 10912623Sphk /* Finally: sort by oid */ 11012623Sphk j = l->ls_length; 11112623Sphk oidpp = (struct sysctl_oid **) l->ls_items; 11212152Sphk for (; j--; oidpp++) { 11312152Sphk if (!*oidpp) 11412152Sphk continue; 11512152Sphk if ((*oidpp)->oid_arg1 == arg) { 11612152Sphk *oidpp = 0; 11712152Sphk continue; 11812152Sphk } 11912243Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 12012152Sphk if (!(*oidpp)->oid_handler) 12112152Sphk sysctl_order((*oidpp)->oid_arg1); 12212152Sphk } 12312152Sphk qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 12412152Sphk sysctl_order_cmp); 12512152Sphk} 12612152Sphk 12712243SphkSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_); 12812152Sphk 12912623Sphk/* 13012623Sphk * "Staff-functions" 13112623Sphk * 13212650Sphk * These functions implement a presently undocumented interface 13312650Sphk * used by the sysctl program to walk the tree, and get the type 13412650Sphk * so it can print the value. 13512650Sphk * This interface is under work and consideration, and should probably 13612650Sphk * be killed with a big axe by the first person who can find the time. 13712650Sphk * (be aware though, that the proper interface isn't as obvious as it 13812650Sphk * may seem, there are various conflicting requirements. 13912650Sphk * 14012623Sphk * {0,0} printf the entire MIB-tree. 14112623Sphk * {0,1,...} return the name of the "..." OID. 14212623Sphk * {0,2,...} return the next OID. 14312623Sphk * {0,3} return the OID of the name in "new" 14412650Sphk * {0,4,...} return the kind & format info for the "..." OID. 14512623Sphk */ 14612623Sphk 14712152Sphkstatic void 14812243Sphksysctl_sysctl_debug_dump_node(struct linker_set *l, int i) 14912152Sphk{ 15012243Sphk int j, k; 15112152Sphk struct sysctl_oid **oidpp; 15212152Sphk 15312152Sphk j = l->ls_length; 15412152Sphk oidpp = (struct sysctl_oid **) l->ls_items; 15512152Sphk for (; j--; oidpp++) { 15612152Sphk 15712152Sphk if (!*oidpp) 15812152Sphk continue; 15912152Sphk 16012152Sphk for (k=0; k<i; k++) 16112152Sphk printf(" "); 16212152Sphk 16312152Sphk if ((*oidpp)->oid_number > 100) { 16412171Sphk printf("Junk! %p # %d %s k %x a1 %p a2 %x h %p\n", 16512152Sphk *oidpp, 16612152Sphk (*oidpp)->oid_number, (*oidpp)->oid_name, 16712152Sphk (*oidpp)->oid_kind, (*oidpp)->oid_arg1, 16812152Sphk (*oidpp)->oid_arg2, (*oidpp)->oid_handler); 16912152Sphk continue; 17012152Sphk } 17112152Sphk printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 17212152Sphk 17312152Sphk printf("%c%c", 17412152Sphk (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 17512152Sphk (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 17612152Sphk 17712152Sphk switch ((*oidpp)->oid_kind & CTLTYPE) { 17812243Sphk case CTLTYPE_NODE: 17912152Sphk if ((*oidpp)->oid_handler) { 18012243Sphk printf(" Node(proc)\n"); 18112152Sphk } else { 18212243Sphk printf(" Node\n"); 18312152Sphk sysctl_sysctl_debug_dump_node( 18412243Sphk (*oidpp)->oid_arg1, i+2); 18512152Sphk } 18612152Sphk break; 18712152Sphk case CTLTYPE_INT: printf(" Int\n"); break; 18812152Sphk case CTLTYPE_STRING: printf(" String\n"); break; 18912152Sphk case CTLTYPE_QUAD: printf(" Quad\n"); break; 19012152Sphk case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 19112152Sphk default: printf("\n"); 19212152Sphk } 19312152Sphk 19412152Sphk } 19512152Sphk} 19612152Sphk 19712152Sphkstatic int 19812152Sphksysctl_sysctl_debug SYSCTL_HANDLER_ARGS 19912152Sphk{ 20012243Sphk sysctl_sysctl_debug_dump_node(&sysctl_, 0); 20112152Sphk return ENOENT; 20212152Sphk} 20312152Sphk 20412152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 20512623Sphk 0, 0, sysctl_sysctl_debug, "-", ""); 20612152Sphk 20712623Sphkstatic int 20812623Sphksysctl_sysctl_name SYSCTL_HANDLER_ARGS 20912623Sphk{ 21012623Sphk int *name = (int *) arg1; 21112623Sphk u_int namelen = arg2; 21212623Sphk int i, j, error = 0; 21312623Sphk struct sysctl_oid **oidpp; 21412623Sphk struct linker_set *lsp = &sysctl_; 21512623Sphk char buf[10]; 21612131Sphk 21712623Sphk while (namelen) { 21812623Sphk if (!lsp) { 21912623Sphk sprintf(buf,"%d",*name); 22012623Sphk if (req->oldidx) 22112623Sphk error = SYSCTL_OUT(req, ".", 1); 22212623Sphk if (!error) 22312623Sphk error = SYSCTL_OUT(req, buf, strlen(buf)); 22412623Sphk if (error) 22512623Sphk return (error); 22612623Sphk namelen--; 22712623Sphk name++; 22812623Sphk continue; 22912623Sphk } 23012623Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 23112623Sphk j = lsp->ls_length; 23212623Sphk lsp = 0; 23312623Sphk for (i = 0; i < j; i++, oidpp++) { 23412623Sphk if (*oidpp && ((*oidpp)->oid_number != *name)) 23512623Sphk continue; 23612131Sphk 23712623Sphk if (req->oldidx) 23812623Sphk error = SYSCTL_OUT(req, ".", 1); 23912623Sphk if (!error) 24012623Sphk error = SYSCTL_OUT(req, (*oidpp)->oid_name, 24112623Sphk strlen((*oidpp)->oid_name)); 24212623Sphk if (error) 24312623Sphk return (error); 24412623Sphk 24512623Sphk namelen--; 24612623Sphk name++; 24712623Sphk 24812623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 24912623Sphk break; 25012623Sphk 25112623Sphk if ((*oidpp)->oid_handler) 25212623Sphk break; 25312623Sphk 25412623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 25512623Sphk break; 25612623Sphk } 25712623Sphk } 25812623Sphk return (SYSCTL_OUT(req, "", 1)); 25912623Sphk} 26012623Sphk 26112623SphkSYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); 26212623Sphk 26312623Sphkstatic int 26412623Sphksysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen, 26512623Sphk int *next, int *len, int level, struct sysctl_oid **oidp) 26612623Sphk{ 26712623Sphk int i, j; 26812623Sphk struct sysctl_oid **oidpp; 26912623Sphk 27012623Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 27112623Sphk j = lsp->ls_length; 27212623Sphk *len = level; 27312623Sphk for (i = 0; i < j; i++, oidpp++) { 27412623Sphk if (!*oidpp) 27512623Sphk continue; 27612623Sphk 27712623Sphk *next = (*oidpp)->oid_number; 27812623Sphk *oidp = *oidpp; 27912623Sphk 28012623Sphk if (!namelen) { 28112623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 28212623Sphk return 0; 28312623Sphk if ((*oidpp)->oid_handler) 28412623Sphk /* We really should call the handler here...*/ 28512623Sphk return 0; 28612623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 28712623Sphk return (sysctl_sysctl_next_ls (lsp, 0, 0, next+1, 28812623Sphk len, level+1, oidp)); 28912623Sphk } 29012623Sphk 29112623Sphk if ((*oidpp)->oid_number < *name) 29212623Sphk continue; 29312623Sphk 29412623Sphk if ((*oidpp)->oid_number > *name) { 29512623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 29612623Sphk return 0; 29712623Sphk if ((*oidpp)->oid_handler) 29812623Sphk return 0; 29912623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 30012623Sphk if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, 30112623Sphk next+1, len, level+1, oidp)) 30212623Sphk return (0); 30312623Sphk namelen = 1; 30412623Sphk *len = level; 30512623Sphk continue; 30612623Sphk } 30712623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 30812623Sphk continue; 30912623Sphk 31012623Sphk if ((*oidpp)->oid_handler) 31112623Sphk continue; 31212623Sphk 31312623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 31412623Sphk if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1, 31512623Sphk len, level+1, oidp)) 31612623Sphk return (0); 31712623Sphk namelen = 1; 31812623Sphk *len = level; 31912623Sphk } 32012623Sphk return 1; 32112623Sphk} 32212623Sphk 32312623Sphkstatic int 32412623Sphksysctl_sysctl_next SYSCTL_HANDLER_ARGS 32512623Sphk{ 32612623Sphk int *name = (int *) arg1; 32712623Sphk u_int namelen = arg2; 32812623Sphk int i, j, error; 32912623Sphk struct sysctl_oid *oid; 33012623Sphk struct linker_set *lsp = &sysctl_; 33112623Sphk int newoid[CTL_MAXNAME]; 33212623Sphk 33312623Sphk i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid); 33412623Sphk if (i) 33512623Sphk return ENOENT; 33612650Sphk error = SYSCTL_OUT(req, newoid, j * sizeof (int)); 33712623Sphk return (error); 33812623Sphk} 33912623Sphk 34012623SphkSYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, ""); 34112623Sphk 34212623Sphkstatic int 34312623Sphkname2oid (char *name, int *oid, int *len, struct sysctl_oid **oidp) 34412623Sphk{ 34512623Sphk int i, j; 34612623Sphk struct sysctl_oid **oidpp; 34712623Sphk struct linker_set *lsp = &sysctl_; 34812623Sphk char *p; 34912623Sphk 35012623Sphk if (!*name) 35112623Sphk return ENOENT; 35212623Sphk 35312623Sphk p = name + strlen(name) - 1 ; 35412623Sphk if (*p == '.') 35512623Sphk *p = '\0'; 35612623Sphk 35712623Sphk *len = 0; 35812623Sphk 35912623Sphk for (p = name; *p && *p != '.'; p++) 36012623Sphk ; 36112623Sphk i = *p; 36212623Sphk if (i == '.') 36312623Sphk *p = '\0'; 36412623Sphk 36512623Sphk j = lsp->ls_length; 36612623Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 36712623Sphk 36812623Sphk while (j-- && *len < CTL_MAXNAME) { 36912623Sphk if (!*oidpp) 37012623Sphk continue; 37112623Sphk if (strcmp(name, (*oidpp)->oid_name)) { 37212623Sphk oidpp++; 37312623Sphk continue; 37412623Sphk } 37512623Sphk *oid++ = (*oidpp)->oid_number; 37612623Sphk (*len)++; 37712623Sphk 37812623Sphk if (!i) { 37912623Sphk if (oidp) 38012623Sphk *oidp = *oidpp; 38112623Sphk return (0); 38212623Sphk } 38312623Sphk 38412623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 38512623Sphk break; 38612623Sphk 38712623Sphk if ((*oidpp)->oid_handler) 38812623Sphk break; 38912623Sphk 39012623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 39112623Sphk j = lsp->ls_length; 39212623Sphk oidpp = (struct sysctl_oid **)lsp->ls_items; 39312623Sphk name = p+1; 39412623Sphk for (p = name; *p && *p != '.'; p++) 39512623Sphk ; 39612623Sphk i = *p; 39712623Sphk if (i == '.') 39812623Sphk *p = '\0'; 39912623Sphk } 40012623Sphk return ENOENT; 40112623Sphk} 40212623Sphk 40312623Sphkstatic int 40412623Sphksysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS 40512623Sphk{ 40612623Sphk char *p; 40712623Sphk int error, oid[CTL_MAXNAME], len; 40812623Sphk struct sysctl_oid *op = 0; 40912623Sphk 41012623Sphk if (!req->newlen) 41112623Sphk return ENOENT; 41212623Sphk 41312623Sphk p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK); 41412623Sphk 41512623Sphk error = SYSCTL_IN(req, p, req->newlen); 41612623Sphk if (error) { 41712623Sphk free(p, M_SYSCTL); 41812623Sphk return (error); 41912623Sphk } 42012623Sphk 42112623Sphk p [req->newlen] = '\0'; 42212623Sphk 42312623Sphk error = name2oid(p, oid, &len, &op); 42412623Sphk 42512623Sphk free(p, M_SYSCTL); 42612623Sphk 42712623Sphk if (error) 42812623Sphk return (error); 42912623Sphk 43012650Sphk error = SYSCTL_OUT(req, oid, len * sizeof *oid); 43112623Sphk return (error); 43212623Sphk} 43312623Sphk 43412910SphkSYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 43512623Sphk sysctl_sysctl_name2oid, "I", ""); 43612623Sphk 43712623Sphkstatic int 43812623Sphksysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS 43912623Sphk{ 44012650Sphk int *name = (int *) arg1, error; 44112623Sphk u_int namelen = arg2; 44212623Sphk int indx, j; 44312623Sphk struct sysctl_oid **oidpp; 44412623Sphk struct linker_set *lsp = &sysctl_; 44512623Sphk 44612623Sphk j = lsp->ls_length; 44712623Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 44812623Sphk 44912623Sphk indx = 0; 45012623Sphk while (j-- && indx < CTL_MAXNAME) { 45112623Sphk if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 45212623Sphk indx++; 45312623Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 45412623Sphk if ((*oidpp)->oid_handler) 45512623Sphk goto found; 45612623Sphk if (indx == namelen) 45712650Sphk goto found; 45812623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 45912623Sphk j = lsp->ls_length; 46012623Sphk oidpp = (struct sysctl_oid **)lsp->ls_items; 46112623Sphk } else { 46212623Sphk if (indx != namelen) 46312623Sphk return EISDIR; 46412623Sphk goto found; 46512623Sphk } 46612623Sphk } else { 46712623Sphk oidpp++; 46812623Sphk } 46912623Sphk } 47012623Sphk return ENOENT; 47112623Sphkfound: 47212623Sphk if (!(*oidpp)->oid_fmt) 47312623Sphk return ENOENT; 47412650Sphk error = SYSCTL_OUT(req, 47512650Sphk &(*oidpp)->oid_kind, sizeof((*oidpp)->oid_kind)); 47612650Sphk if (!error) 47712650Sphk error = SYSCTL_OUT(req, (*oidpp)->oid_fmt, 47812650Sphk strlen((*oidpp)->oid_fmt)+1); 47912650Sphk return (error); 48012623Sphk} 48112623Sphk 48212623Sphk 48312623SphkSYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, ""); 48412623Sphk 48512243Sphk/* 48612623Sphk * Default "handler" functions. 48712623Sphk */ 48812623Sphk 48912623Sphk/* 49012243Sphk * Handle an integer, signed or unsigned. 49112243Sphk * Two cases: 49212243Sphk * a variable: point arg1 at it. 49312243Sphk * a constant: pass it in arg2. 49412243Sphk */ 49512243Sphk 49611865Sphkint 49711865Sphksysctl_handle_int SYSCTL_HANDLER_ARGS 49811863Sphk{ 49912243Sphk int error = 0; 50011863Sphk 50112243Sphk if (arg1) 50212243Sphk error = SYSCTL_OUT(req, arg1, sizeof(int)); 50312243Sphk else if (arg2) 50412243Sphk error = SYSCTL_OUT(req, &arg2, sizeof(int)); 50511863Sphk 50612243Sphk if (error || !req->newptr) 50712243Sphk return (error); 50811863Sphk 50912243Sphk if (!arg1) 51012243Sphk error = EPERM; 51112243Sphk else 51212243Sphk error = SYSCTL_IN(req, arg1, sizeof(int)); 51312243Sphk return (error); 51411863Sphk} 51511863Sphk 51612243Sphk/* 51712243Sphk * Handle our generic '\0' terminated 'C' string. 51812243Sphk * Two cases: 51912243Sphk * a variable string: point arg1 at it, arg2 is max length. 52012243Sphk * a constant string: point arg1 at it, arg2 is zero. 52112243Sphk */ 52212243Sphk 52311865Sphkint 52411865Sphksysctl_handle_string SYSCTL_HANDLER_ARGS 52511863Sphk{ 52612243Sphk int error=0; 52711863Sphk 52812297Sphk error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1); 52911863Sphk 53012260Sphk if (error || !req->newptr || !arg2) 53112243Sphk return (error); 53211863Sphk 53312243Sphk if ((req->newlen - req->newidx) > arg2) { 53412243Sphk error = E2BIG; 53512243Sphk } else { 53612243Sphk arg2 = (req->newlen - req->newidx); 53712243Sphk error = SYSCTL_IN(req, arg1, arg2); 53812243Sphk ((char *)arg1)[arg2] = '\0'; 53911863Sphk } 54012131Sphk 54112131Sphk return (error); 54211863Sphk} 54311863Sphk 54412243Sphk/* 54512243Sphk * Handle any kind of opaque data. 54612243Sphk * arg1 points to it, arg2 is the size. 54712243Sphk */ 54812243Sphk 54911865Sphkint 55011865Sphksysctl_handle_opaque SYSCTL_HANDLER_ARGS 55111863Sphk{ 55212243Sphk int error; 55312243Sphk 55412243Sphk error = SYSCTL_OUT(req, arg1, arg2); 55512243Sphk 55612243Sphk if (error || !req->newptr) 55712243Sphk return (error); 55812243Sphk 55912243Sphk error = SYSCTL_IN(req, arg1, arg2); 56012243Sphk 56112243Sphk return (error); 56212243Sphk} 56312243Sphk 56412260Sphk/* 56512260Sphk * Transfer functions to/from kernel space. 56612260Sphk * XXX: rather untested at this point 56712260Sphk */ 56812260Sphkstatic int 56912910Sphksysctl_old_kernel(struct sysctl_req *req, const void *p, int l) 57012243Sphk{ 57112260Sphk int i = 0; 57212260Sphk 57312260Sphk if (req->oldptr) { 57412260Sphk i = min(req->oldlen - req->oldidx, l); 57512260Sphk if (i > 0) 57612260Sphk bcopy(p, req->oldptr + req->oldidx, i); 57712243Sphk } 57812260Sphk req->oldidx += l; 57912243Sphk if (i != l) 58011863Sphk return (ENOMEM); 58112260Sphk return (0); 58211863Sphk 58312243Sphk} 58412243Sphk 58512260Sphkstatic int 58612910Sphksysctl_new_kernel(struct sysctl_req *req, const void *p, int l) 58712243Sphk{ 58812260Sphk if (!req->newptr) 58912260Sphk return 0; 59012260Sphk if (req->newlen - req->newidx < l) 59111863Sphk return (EINVAL); 59213155Speter bcopy(p, req->newptr + req->newidx, l); 59312243Sphk req->newidx += l; 59412131Sphk return (0); 59511863Sphk} 59611863Sphk 59712260Sphk/* 59812260Sphk * Transfer function to/from user space. 59912260Sphk */ 60012260Sphkstatic int 60112910Sphksysctl_old_user(struct sysctl_req *req, const void *p, int l) 60212243Sphk{ 60312260Sphk int error = 0, i = 0; 60412243Sphk 60512429Sphk if (req->lock == 1 && req->oldptr) { 60612429Sphk vslock(req->oldptr, req->oldlen); 60712429Sphk req->lock = 2; 60812429Sphk } 60912260Sphk if (req->oldptr) { 61012260Sphk i = min(req->oldlen - req->oldidx, l); 61112260Sphk if (i > 0) 61212260Sphk error = copyout(p, req->oldptr + req->oldidx, i); 61312260Sphk } 61412260Sphk req->oldidx += l; 61512243Sphk if (error) 61612243Sphk return (error); 61712260Sphk if (req->oldptr && i < l) 61812243Sphk return (ENOMEM); 61912260Sphk return (0); 62012243Sphk} 62112243Sphk 62212260Sphkstatic int 62312243Sphksysctl_new_user(struct sysctl_req *req, void *p, int l) 62412243Sphk{ 62512285Sphk int error; 62612260Sphk 62712260Sphk if (!req->newptr) 62812260Sphk return 0; 62912260Sphk if (req->newlen - req->newidx < l) 63012243Sphk return (EINVAL); 63112243Sphk error = copyin(req->newptr + req->newidx, p, l); 63212243Sphk req->newidx += l; 63312243Sphk return (error); 63412243Sphk} 63512243Sphk 6361541Srgrimes/* 63712131Sphk * Traverse our tree, and find the right node, execute whatever it points 63812131Sphk * at, and return the resulting error code. 63912131Sphk */ 64012131Sphk 6411541Srgrimesint 64212131Sphksysctl_root SYSCTL_HANDLER_ARGS 64312131Sphk{ 64412131Sphk int *name = (int *) arg1; 64512623Sphk u_int namelen = arg2; 64612131Sphk int indx, i, j; 64712131Sphk struct sysctl_oid **oidpp; 64812131Sphk struct linker_set *lsp = &sysctl_; 64912131Sphk 65012131Sphk j = lsp->ls_length; 65112131Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 65212131Sphk 65312131Sphk indx = 0; 65412131Sphk while (j-- && indx < CTL_MAXNAME) { 65512152Sphk if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 65612131Sphk indx++; 65712429Sphk if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK) 65812429Sphk req->lock = 0; 65912131Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 66012131Sphk if ((*oidpp)->oid_handler) 66112131Sphk goto found; 66212243Sphk if (indx == namelen) 66312131Sphk return ENOENT; 66412131Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 66512131Sphk j = lsp->ls_length; 66612131Sphk oidpp = (struct sysctl_oid **)lsp->ls_items; 66712131Sphk } else { 66812243Sphk if (indx != namelen) 66912131Sphk return EISDIR; 67012131Sphk goto found; 67112131Sphk } 67212131Sphk } else { 67312131Sphk oidpp++; 67412131Sphk } 67512131Sphk } 67612260Sphk return ENOENT; 67712131Sphkfound: 67812131Sphk /* If writing isn't allowed */ 67912243Sphk if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR)) 68012131Sphk return (EPERM); 68112131Sphk 68212910Sphk /* Most likely only root can write */ 68312910Sphk if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) && 68412910Sphk req->newptr && req->p && 68512910Sphk (i = suser(req->p->p_ucred, &req->p->p_acflag))) 68612910Sphk return (i); 68712910Sphk 68812243Sphk if (!(*oidpp)->oid_handler) 68912131Sphk return EINVAL; 69012131Sphk 69112131Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 69212131Sphk i = ((*oidpp)->oid_handler) (*oidpp, 69312131Sphk name + indx, namelen - indx, 69412243Sphk req); 69512131Sphk } else { 69612131Sphk i = ((*oidpp)->oid_handler) (*oidpp, 69712131Sphk (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 69812243Sphk req); 69912131Sphk } 70012131Sphk return (i); 70112131Sphk} 70212131Sphk 70312221Sbde#ifndef _SYS_SYSPROTO_H_ 70412171Sphkstruct sysctl_args { 70512171Sphk int *name; 70612171Sphk u_int namelen; 70712171Sphk void *old; 70812171Sphk size_t *oldlenp; 70912171Sphk void *new; 71012171Sphk size_t newlen; 71112171Sphk}; 71212221Sbde#endif 71312171Sphk 71412131Sphkint 71512429Sphk__sysctl(struct proc *p, struct sysctl_args *uap, int *retval) 7161541Srgrimes{ 71712260Sphk int error, i, j, name[CTL_MAXNAME]; 7181541Srgrimes 7191541Srgrimes if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 7201541Srgrimes return (EINVAL); 72111863Sphk 7223308Sphk error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 7233308Sphk if (error) 7241541Srgrimes return (error); 7251541Srgrimes 72612260Sphk error = userland_sysctl(p, name, uap->namelen, 72712171Sphk uap->old, uap->oldlenp, 0, 72812260Sphk uap->new, uap->newlen, &j); 72912260Sphk if (error && error != ENOMEM) 73012260Sphk return (error); 73112260Sphk if (uap->oldlenp) { 73212260Sphk i = copyout(&j, uap->oldlenp, sizeof(j)); 73312260Sphk if (i) 73412260Sphk return (i); 73512260Sphk } 73612260Sphk return (error); 73712171Sphk} 73812171Sphk 73912171Sphk/* 74012171Sphk * This is used from various compatibility syscalls too. That's why name 74112171Sphk * must be in kernel space. 74212171Sphk */ 74312171Sphkint 74412171Sphkuserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval) 74512171Sphk{ 74612429Sphk int error = 0; 74712243Sphk struct sysctl_req req; 74812171Sphk 74912243Sphk bzero(&req, sizeof req); 75012243Sphk 75112285Sphk req.p = p; 75212285Sphk 75312171Sphk if (oldlenp) { 75412171Sphk if (inkernel) { 75512243Sphk req.oldlen = *oldlenp; 75612171Sphk } else { 75712260Sphk error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); 75812171Sphk if (error) 75912171Sphk return (error); 76012171Sphk } 76112171Sphk } 76212171Sphk 76312243Sphk if (old) { 76412243Sphk if (!useracc(old, req.oldlen, B_WRITE)) 76512243Sphk return (EFAULT); 76612243Sphk req.oldptr= old; 76712243Sphk } 76812131Sphk 76912171Sphk if (newlen) { 77012243Sphk if (!useracc(new, req.newlen, B_READ)) 77112243Sphk return (EFAULT); 77212243Sphk req.newlen = newlen; 77312243Sphk req.newptr = new; 77411863Sphk } 77512131Sphk 77612243Sphk req.oldfunc = sysctl_old_user; 77712243Sphk req.newfunc = sysctl_new_user; 77812429Sphk req.lock = 1; 77911863Sphk 78012429Sphk /* XXX this should probably be done in a general way */ 78112429Sphk while (memlock.sl_lock) { 78212429Sphk memlock.sl_want = 1; 78312429Sphk (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 78412429Sphk memlock.sl_locked++; 78512429Sphk } 78612429Sphk memlock.sl_lock = 1; 78712429Sphk 78812243Sphk error = sysctl_root(0, name, namelen, &req); 78912243Sphk 79012429Sphk if (req.lock == 2) 79112429Sphk vsunlock(req.oldptr, req.oldlen, B_WRITE); 79212429Sphk 79312429Sphk memlock.sl_lock = 0; 79412429Sphk 79512429Sphk if (memlock.sl_want) { 79612429Sphk memlock.sl_want = 0; 79712429Sphk wakeup((caddr_t)&memlock); 79812429Sphk } 79912429Sphk 80012260Sphk if (error && error != ENOMEM) 80112260Sphk return (error); 80212260Sphk 80312260Sphk if (retval) { 80412260Sphk if (req.oldptr && req.oldidx > req.oldlen) 80512243Sphk *retval = req.oldlen; 80612260Sphk else 80712260Sphk *retval = req.oldidx; 80811863Sphk } 80912260Sphk return (error); 8101541Srgrimes} 8111541Srgrimes 8121541Srgrimes#ifdef COMPAT_43 8131541Srgrimes#include <sys/socket.h> 81415103Sphk#include <vm/vm_param.h> 81515103Sphk 8161541Srgrimes#define KINFO_PROC (0<<8) 8171541Srgrimes#define KINFO_RT (1<<8) 8181541Srgrimes#define KINFO_VNODE (2<<8) 8191541Srgrimes#define KINFO_FILE (3<<8) 8201541Srgrimes#define KINFO_METER (4<<8) 8211541Srgrimes#define KINFO_LOADAVG (5<<8) 8221541Srgrimes#define KINFO_CLOCKRATE (6<<8) 8231541Srgrimes 8249455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 8259455Speter#define KINFO_BSDI_SYSINFO (101<<8) 8269455Speter 8279455Speter/* 8289455Speter * XXX this is bloat, but I hope it's better here than on the potentially 8299455Speter * limited kernel stack... -Peter 8309455Speter */ 8319455Speter 83212819Sphkstatic struct { 8339455Speter int bsdi_machine; /* "i386" on BSD/386 */ 8349455Speter/* ^^^ this is an offset to the string, relative to the struct start */ 8359455Speter char *pad0; 8369455Speter long pad1; 8379455Speter long pad2; 8389455Speter long pad3; 8399455Speter u_long pad4; 8409455Speter u_long pad5; 8419455Speter u_long pad6; 8429455Speter 8439455Speter int bsdi_ostype; /* "BSD/386" on BSD/386 */ 8449455Speter int bsdi_osrelease; /* "1.1" on BSD/386 */ 8459455Speter long pad7; 8469455Speter long pad8; 8479455Speter char *pad9; 8489455Speter 8499455Speter long pad10; 8509455Speter long pad11; 8519455Speter int pad12; 8529455Speter long pad13; 8539455Speter quad_t pad14; 8549455Speter long pad15; 8559455Speter 8569455Speter struct timeval pad16; 8579455Speter /* we dont set this, because BSDI's uname used gethostname() instead */ 8589455Speter int bsdi_hostname; /* hostname on BSD/386 */ 8599455Speter 8609455Speter /* the actual string data is appended here */ 8619455Speter 8629455Speter} bsdi_si; 8639455Speter/* 8649455Speter * this data is appended to the end of the bsdi_si structure during copyout. 8659455Speter * The "char *" offsets are relative to the base of the bsdi_si struct. 8669455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 8679455Speter * should not exceed the length of the buffer here... (or else!! :-) 8689455Speter */ 86912819Sphkstatic char bsdi_strings[80]; /* It had better be less than this! */ 8709455Speter 87112221Sbde#ifndef _SYS_SYSPROTO_H_ 8721541Srgrimesstruct getkerninfo_args { 8731541Srgrimes int op; 8741541Srgrimes char *where; 8751541Srgrimes int *size; 8761541Srgrimes int arg; 8771541Srgrimes}; 87812221Sbde#endif 8791541Srgrimes 8801549Srgrimesint 88112429Sphkogetkerninfo(struct proc *p, struct getkerninfo_args *uap, int *retval) 8821541Srgrimes{ 88312171Sphk int error, name[6]; 8841541Srgrimes u_int size; 8851541Srgrimes 8861541Srgrimes switch (uap->op & 0xff00) { 8871541Srgrimes 8881541Srgrimes case KINFO_RT: 88912171Sphk name[0] = CTL_NET; 89012171Sphk name[1] = PF_ROUTE; 89112171Sphk name[2] = 0; 89212171Sphk name[3] = (uap->op & 0xff0000) >> 16; 89312171Sphk name[4] = uap->op & 0xff; 89412171Sphk name[5] = uap->arg; 89512171Sphk error = userland_sysctl(p, name, 6, uap->where, uap->size, 89612429Sphk 0, 0, 0, &size); 8971541Srgrimes break; 8981541Srgrimes 8991541Srgrimes case KINFO_VNODE: 90012171Sphk name[0] = CTL_KERN; 90112171Sphk name[1] = KERN_VNODE; 90212171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 90312429Sphk 0, 0, 0, &size); 9041541Srgrimes break; 9051541Srgrimes 9061541Srgrimes case KINFO_PROC: 90712171Sphk name[0] = CTL_KERN; 90812171Sphk name[1] = KERN_PROC; 90912171Sphk name[2] = uap->op & 0xff; 91012171Sphk name[3] = uap->arg; 91112171Sphk error = userland_sysctl(p, name, 4, uap->where, uap->size, 91212429Sphk 0, 0, 0, &size); 9131541Srgrimes break; 9141541Srgrimes 9151541Srgrimes case KINFO_FILE: 91612171Sphk name[0] = CTL_KERN; 91712171Sphk name[1] = KERN_FILE; 91812171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 91912429Sphk 0, 0, 0, &size); 9201541Srgrimes break; 9211541Srgrimes 9221541Srgrimes case KINFO_METER: 92312171Sphk name[0] = CTL_VM; 92412171Sphk name[1] = VM_METER; 92512171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 92612429Sphk 0, 0, 0, &size); 9271541Srgrimes break; 9281541Srgrimes 9291541Srgrimes case KINFO_LOADAVG: 93012171Sphk name[0] = CTL_VM; 93112171Sphk name[1] = VM_LOADAVG; 93212171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 93312429Sphk 0, 0, 0, &size); 9341541Srgrimes break; 9351541Srgrimes 9361541Srgrimes case KINFO_CLOCKRATE: 93712171Sphk name[0] = CTL_KERN; 93812171Sphk name[1] = KERN_CLOCKRATE; 93912171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 94012429Sphk 0, 0, 0, &size); 9411541Srgrimes break; 9421541Srgrimes 9439455Speter case KINFO_BSDI_SYSINFO: { 9449455Speter /* 9459455Speter * this is pretty crude, but it's just enough for uname() 9469455Speter * from BSDI's 1.x libc to work. 9479455Speter * 9489455Speter * In particular, it doesn't return the same results when 9499455Speter * the supplied buffer is too small. BSDI's version apparently 9509455Speter * will return the amount copied, and set the *size to how 9519455Speter * much was needed. The emulation framework here isn't capable 9529455Speter * of that, so we just set both to the amount copied. 9539455Speter * BSDI's 2.x product apparently fails with ENOMEM in this 9549455Speter * scenario. 9559455Speter */ 9569455Speter 9579455Speter u_int needed; 9589455Speter u_int left; 9599455Speter char *s; 9609455Speter 9619455Speter bzero((char *)&bsdi_si, sizeof(bsdi_si)); 9629455Speter bzero(bsdi_strings, sizeof(bsdi_strings)); 9639455Speter 9649455Speter s = bsdi_strings; 9659455Speter 9669455Speter bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 9679455Speter strcpy(s, ostype); 9689455Speter s += strlen(s) + 1; 9699455Speter 9709455Speter bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 9719455Speter strcpy(s, osrelease); 9729455Speter s += strlen(s) + 1; 9739455Speter 9749455Speter bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 9759455Speter strcpy(s, machine); 9769455Speter s += strlen(s) + 1; 9779455Speter 9789455Speter needed = sizeof(bsdi_si) + (s - bsdi_strings); 9799455Speter 9809455Speter if (uap->where == NULL) { 9819455Speter /* process is asking how much buffer to supply.. */ 9829455Speter size = needed; 9839455Speter error = 0; 9849455Speter break; 9859455Speter } 9869455Speter 9879455Speter 9889455Speter /* if too much buffer supplied, trim it down */ 9899455Speter if (size > needed) 9909455Speter size = needed; 9919455Speter 9929455Speter /* how much of the buffer is remaining */ 9939455Speter left = size; 9949455Speter 9959455Speter if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 9969455Speter break; 9979455Speter 9989455Speter /* is there any point in continuing? */ 9999455Speter if (left > sizeof(bsdi_si)) { 10009455Speter left -= sizeof(bsdi_si); 10019455Speter error = copyout(&bsdi_strings, 10029455Speter uap->where + sizeof(bsdi_si), left); 10039455Speter } 10049455Speter break; 10059455Speter } 10069455Speter 10071541Srgrimes default: 10081541Srgrimes return (EOPNOTSUPP); 10091541Srgrimes } 10101541Srgrimes if (error) 10111541Srgrimes return (error); 10121541Srgrimes *retval = size; 10131541Srgrimes if (uap->size) 10141541Srgrimes error = copyout((caddr_t)&size, (caddr_t)uap->size, 10151541Srgrimes sizeof(size)); 10161541Srgrimes return (error); 10171541Srgrimes} 10181541Srgrimes#endif /* COMPAT_43 */ 1019