kern_sysctl.c revision 31778
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 4031778Seivind * $Id: kern_sysctl.c,v 1.73 1997/11/06 19:29:15 phk Exp $ 411541Srgrimes */ 421541Srgrimes 4331778Seivind#include "opt_compat.h" 4431778Seivind 451541Srgrimes#include <sys/param.h> 4624744Sbde#include <sys/buf.h> 471541Srgrimes#include <sys/kernel.h> 481541Srgrimes#include <sys/sysctl.h> 4912623Sphk#include <sys/malloc.h> 5012662Sdg#include <sys/proc.h> 5115103Sphk#include <sys/systm.h> 5215103Sphk#include <sys/sysproto.h> 5312645Sbde#include <vm/vm.h> 5412662Sdg#include <vm/vm_extern.h> 5512645Sbde 5630354Sphkstatic MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic"); 5730309Sphk 5812429Sphk/* 5912429Sphk * Locking and stats 6012429Sphk */ 6112429Sphkstatic struct sysctl_lock { 6212429Sphk int sl_lock; 6312429Sphk int sl_want; 6412429Sphk int sl_locked; 6512429Sphk} memlock; 6612429Sphk 6712429Sphkstatic int sysctl_root SYSCTL_HANDLER_ARGS; 6812429Sphk 6912152Sphkextern struct linker_set sysctl_; 7012152Sphk 7112623Sphk/* 7212623Sphk * Initialization of the MIB tree. 7312623Sphk * 7412623Sphk * Order by number in each linker_set. 7512623Sphk */ 7612429Sphk 7712429Sphkstatic int 7812197Sbdesysctl_order_cmp(const void *a, const void *b) 7912152Sphk{ 8018025Sbde struct sysctl_oid const * const *pa; 8118025Sbde struct sysctl_oid const * const *pb; 8212197Sbde 8318025Sbde pa = (struct sysctl_oid const * const *)a; 8418025Sbde pb = (struct sysctl_oid const * const *)b; 8512197Sbde if (*pa == NULL) 8612197Sbde return (1); 8712197Sbde if (*pb == NULL) 8812197Sbde return (-1); 8912152Sphk return ((*pa)->oid_number - (*pb)->oid_number); 9012152Sphk} 9112131Sphk 9212152Sphkstatic void 9312152Sphksysctl_order(void *arg) 9412152Sphk{ 9512623Sphk int j, k; 9612152Sphk struct linker_set *l = (struct linker_set *) arg; 9712152Sphk struct sysctl_oid **oidpp; 9812152Sphk 9912623Sphk /* First, find the highest oid we have */ 10012152Sphk j = l->ls_length; 10112152Sphk oidpp = (struct sysctl_oid **) l->ls_items; 10215241Sphk for (k = 0; j--; oidpp++) { 10315241Sphk if ((*oidpp)->oid_arg1 == arg) { 10415241Sphk *oidpp = 0; 10515241Sphk continue; 10615241Sphk } 10712623Sphk if (*oidpp && (*oidpp)->oid_number > k) 10812623Sphk k = (*oidpp)->oid_number; 10915241Sphk } 11012623Sphk 11112623Sphk /* Next, replace all OID_AUTO oids with new numbers */ 11212623Sphk j = l->ls_length; 11312623Sphk oidpp = (struct sysctl_oid **) l->ls_items; 11412623Sphk k += 100; 11512623Sphk for (; j--; oidpp++) 11612623Sphk if (*oidpp && (*oidpp)->oid_number == OID_AUTO) 11712623Sphk (*oidpp)->oid_number = k++; 11812623Sphk 11912623Sphk /* Finally: sort by oid */ 12012623Sphk j = l->ls_length; 12112623Sphk oidpp = (struct sysctl_oid **) l->ls_items; 12212152Sphk for (; j--; oidpp++) { 12312152Sphk if (!*oidpp) 12412152Sphk continue; 12512243Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 12612152Sphk if (!(*oidpp)->oid_handler) 12712152Sphk sysctl_order((*oidpp)->oid_arg1); 12812152Sphk } 12912152Sphk qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 13012152Sphk sysctl_order_cmp); 13112152Sphk} 13212152Sphk 13312243SphkSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_); 13412152Sphk 13512623Sphk/* 13612623Sphk * "Staff-functions" 13712623Sphk * 13812650Sphk * These functions implement a presently undocumented interface 13912650Sphk * used by the sysctl program to walk the tree, and get the type 14012650Sphk * so it can print the value. 14112650Sphk * This interface is under work and consideration, and should probably 14212650Sphk * be killed with a big axe by the first person who can find the time. 14312650Sphk * (be aware though, that the proper interface isn't as obvious as it 14412650Sphk * may seem, there are various conflicting requirements. 14512650Sphk * 14612623Sphk * {0,0} printf the entire MIB-tree. 14712623Sphk * {0,1,...} return the name of the "..." OID. 14812623Sphk * {0,2,...} return the next OID. 14912623Sphk * {0,3} return the OID of the name in "new" 15012650Sphk * {0,4,...} return the kind & format info for the "..." OID. 15112623Sphk */ 15212623Sphk 15312152Sphkstatic void 15412243Sphksysctl_sysctl_debug_dump_node(struct linker_set *l, int i) 15512152Sphk{ 15612243Sphk int j, k; 15712152Sphk struct sysctl_oid **oidpp; 15812152Sphk 15912152Sphk j = l->ls_length; 16012152Sphk oidpp = (struct sysctl_oid **) l->ls_items; 16112152Sphk for (; j--; oidpp++) { 16212152Sphk 16312152Sphk if (!*oidpp) 16412152Sphk continue; 16512152Sphk 16612152Sphk for (k=0; k<i; k++) 16712152Sphk printf(" "); 16812152Sphk 16912152Sphk printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 17012152Sphk 17112152Sphk printf("%c%c", 17212152Sphk (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 17312152Sphk (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 17412152Sphk 17515241Sphk if ((*oidpp)->oid_handler) 17615241Sphk printf(" *Handler"); 17715241Sphk 17812152Sphk switch ((*oidpp)->oid_kind & CTLTYPE) { 17912243Sphk case CTLTYPE_NODE: 18015241Sphk printf(" Node\n"); 18115241Sphk if (!(*oidpp)->oid_handler) { 18212152Sphk sysctl_sysctl_debug_dump_node( 18312243Sphk (*oidpp)->oid_arg1, i+2); 18412152Sphk } 18512152Sphk break; 18612152Sphk case CTLTYPE_INT: printf(" Int\n"); break; 18712152Sphk case CTLTYPE_STRING: printf(" String\n"); break; 18812152Sphk case CTLTYPE_QUAD: printf(" Quad\n"); break; 18912152Sphk case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 19012152Sphk default: printf("\n"); 19112152Sphk } 19212152Sphk 19312152Sphk } 19412152Sphk} 19512152Sphk 19612152Sphkstatic int 19712152Sphksysctl_sysctl_debug SYSCTL_HANDLER_ARGS 19812152Sphk{ 19912243Sphk sysctl_sysctl_debug_dump_node(&sysctl_, 0); 20012152Sphk return ENOENT; 20112152Sphk} 20212152Sphk 20312152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 20412623Sphk 0, 0, sysctl_sysctl_debug, "-", ""); 20512152Sphk 20612623Sphkstatic int 20712623Sphksysctl_sysctl_name SYSCTL_HANDLER_ARGS 20812623Sphk{ 20912623Sphk int *name = (int *) arg1; 21012623Sphk u_int namelen = arg2; 21112623Sphk int i, j, error = 0; 21212623Sphk struct sysctl_oid **oidpp; 21312623Sphk struct linker_set *lsp = &sysctl_; 21412623Sphk char buf[10]; 21512131Sphk 21612623Sphk while (namelen) { 21712623Sphk if (!lsp) { 21812623Sphk sprintf(buf,"%d",*name); 21912623Sphk if (req->oldidx) 22012623Sphk error = SYSCTL_OUT(req, ".", 1); 22112623Sphk if (!error) 22212623Sphk error = SYSCTL_OUT(req, buf, strlen(buf)); 22312623Sphk if (error) 22412623Sphk return (error); 22512623Sphk namelen--; 22612623Sphk name++; 22712623Sphk continue; 22812623Sphk } 22912623Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 23012623Sphk j = lsp->ls_length; 23112623Sphk lsp = 0; 23212623Sphk for (i = 0; i < j; i++, oidpp++) { 23312623Sphk if (*oidpp && ((*oidpp)->oid_number != *name)) 23412623Sphk continue; 23512131Sphk 23612623Sphk if (req->oldidx) 23712623Sphk error = SYSCTL_OUT(req, ".", 1); 23812623Sphk if (!error) 23912623Sphk error = SYSCTL_OUT(req, (*oidpp)->oid_name, 24012623Sphk strlen((*oidpp)->oid_name)); 24112623Sphk if (error) 24212623Sphk return (error); 24312623Sphk 24412623Sphk namelen--; 24512623Sphk name++; 24612623Sphk 24712623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 24812623Sphk break; 24912623Sphk 25012623Sphk if ((*oidpp)->oid_handler) 25112623Sphk break; 25212623Sphk 25312623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 25412623Sphk break; 25512623Sphk } 25612623Sphk } 25712623Sphk return (SYSCTL_OUT(req, "", 1)); 25812623Sphk} 25912623Sphk 26012623SphkSYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); 26112623Sphk 26212623Sphkstatic int 26312623Sphksysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen, 26412623Sphk int *next, int *len, int level, struct sysctl_oid **oidp) 26512623Sphk{ 26612623Sphk int i, j; 26712623Sphk struct sysctl_oid **oidpp; 26812623Sphk 26912623Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 27012623Sphk j = lsp->ls_length; 27112623Sphk *len = level; 27212623Sphk for (i = 0; i < j; i++, oidpp++) { 27312623Sphk if (!*oidpp) 27412623Sphk continue; 27512623Sphk 27612623Sphk *next = (*oidpp)->oid_number; 27712623Sphk *oidp = *oidpp; 27812623Sphk 27912623Sphk if (!namelen) { 28012623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 28112623Sphk return 0; 28212623Sphk if ((*oidpp)->oid_handler) 28312623Sphk /* We really should call the handler here...*/ 28412623Sphk return 0; 28512623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 28615241Sphk if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1, 28715241Sphk len, level+1, oidp)) 28815241Sphk return 0; 28915241Sphk goto next; 29012623Sphk } 29112623Sphk 29212623Sphk if ((*oidpp)->oid_number < *name) 29312623Sphk continue; 29412623Sphk 29512623Sphk if ((*oidpp)->oid_number > *name) { 29612623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 29712623Sphk return 0; 29812623Sphk if ((*oidpp)->oid_handler) 29912623Sphk return 0; 30012623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 30112623Sphk if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, 30212623Sphk next+1, len, level+1, oidp)) 30312623Sphk return (0); 30415241Sphk goto next; 30512623Sphk } 30612623Sphk if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 30712623Sphk continue; 30812623Sphk 30912623Sphk if ((*oidpp)->oid_handler) 31012623Sphk continue; 31112623Sphk 31212623Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 31312623Sphk if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1, 31412623Sphk len, level+1, oidp)) 31512623Sphk return (0); 31615241Sphk next: 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)); 50320506Sbde else 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) 57617971Sbde bcopy(p, (char *)req->oldptr + req->oldidx, i); 57712243Sphk } 57812260Sphk req->oldidx += l; 57916282Snate if (req->oldptr && i != l) 58011863Sphk return (ENOMEM); 58112260Sphk return (0); 58212243Sphk} 58312243Sphk 58412260Sphkstatic int 58516282Snatesysctl_new_kernel(struct sysctl_req *req, void *p, int l) 58612243Sphk{ 58712260Sphk if (!req->newptr) 58812260Sphk return 0; 58912260Sphk if (req->newlen - req->newidx < l) 59011863Sphk return (EINVAL); 59117971Sbde bcopy((char *)req->newptr + req->newidx, p, l); 59212243Sphk req->newidx += l; 59312131Sphk return (0); 59411863Sphk} 59511863Sphk 59616282Snateint 59716282Snatekernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, int *retval) 59816282Snate{ 59916282Snate int error = 0; 60016282Snate struct sysctl_req req; 60116282Snate 60216282Snate bzero(&req, sizeof req); 60316282Snate 60416282Snate req.p = p; 60516282Snate 60616282Snate if (oldlenp) { 60716282Snate req.oldlen = *oldlenp; 60816282Snate } 60916282Snate 61016282Snate if (old) { 61116282Snate req.oldptr= old; 61216282Snate } 61316282Snate 61416282Snate if (newlen) { 61516282Snate req.newlen = newlen; 61616282Snate req.newptr = new; 61716282Snate } 61816282Snate 61916282Snate req.oldfunc = sysctl_old_kernel; 62016282Snate req.newfunc = sysctl_new_kernel; 62116282Snate req.lock = 1; 62216282Snate 62316282Snate /* XXX this should probably be done in a general way */ 62416282Snate while (memlock.sl_lock) { 62516282Snate memlock.sl_want = 1; 62616282Snate (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 62716282Snate memlock.sl_locked++; 62816282Snate } 62916282Snate memlock.sl_lock = 1; 63016282Snate 63116282Snate error = sysctl_root(0, name, namelen, &req); 63216282Snate 63316282Snate if (req.lock == 2) 63416282Snate vsunlock(req.oldptr, req.oldlen, B_WRITE); 63516282Snate 63616282Snate memlock.sl_lock = 0; 63716282Snate 63816282Snate if (memlock.sl_want) { 63916282Snate memlock.sl_want = 0; 64016282Snate wakeup((caddr_t)&memlock); 64116282Snate } 64216282Snate 64316282Snate if (error && error != ENOMEM) 64416282Snate return (error); 64516282Snate 64616282Snate if (retval) { 64716282Snate if (req.oldptr && req.oldidx > req.oldlen) 64816282Snate *retval = req.oldlen; 64916282Snate else 65016282Snate *retval = req.oldidx; 65116282Snate } 65216282Snate return (error); 65316282Snate} 65416282Snate 65512260Sphk/* 65612260Sphk * Transfer function to/from user space. 65712260Sphk */ 65812260Sphkstatic int 65912910Sphksysctl_old_user(struct sysctl_req *req, const void *p, int l) 66012243Sphk{ 66112260Sphk int error = 0, i = 0; 66212243Sphk 66312429Sphk if (req->lock == 1 && req->oldptr) { 66412429Sphk vslock(req->oldptr, req->oldlen); 66512429Sphk req->lock = 2; 66612429Sphk } 66712260Sphk if (req->oldptr) { 66812260Sphk i = min(req->oldlen - req->oldidx, l); 66912260Sphk if (i > 0) 67017971Sbde error = copyout(p, (char *)req->oldptr + req->oldidx, 67117971Sbde i); 67212260Sphk } 67312260Sphk req->oldidx += l; 67412243Sphk if (error) 67512243Sphk return (error); 67612260Sphk if (req->oldptr && i < l) 67712243Sphk return (ENOMEM); 67812260Sphk return (0); 67912243Sphk} 68012243Sphk 68112260Sphkstatic int 68212243Sphksysctl_new_user(struct sysctl_req *req, void *p, int l) 68312243Sphk{ 68412285Sphk int error; 68512260Sphk 68612260Sphk if (!req->newptr) 68712260Sphk return 0; 68812260Sphk if (req->newlen - req->newidx < l) 68912243Sphk return (EINVAL); 69017971Sbde error = copyin((char *)req->newptr + req->newidx, p, l); 69112243Sphk req->newidx += l; 69212243Sphk return (error); 69312243Sphk} 69412243Sphk 6951541Srgrimes/* 69612131Sphk * Traverse our tree, and find the right node, execute whatever it points 69712131Sphk * at, and return the resulting error code. 69812131Sphk */ 69912131Sphk 7001541Srgrimesint 70112131Sphksysctl_root SYSCTL_HANDLER_ARGS 70212131Sphk{ 70312131Sphk int *name = (int *) arg1; 70412623Sphk u_int namelen = arg2; 70512131Sphk int indx, i, j; 70612131Sphk struct sysctl_oid **oidpp; 70712131Sphk struct linker_set *lsp = &sysctl_; 70812131Sphk 70912131Sphk j = lsp->ls_length; 71012131Sphk oidpp = (struct sysctl_oid **) lsp->ls_items; 71112131Sphk 71212131Sphk indx = 0; 71312131Sphk while (j-- && indx < CTL_MAXNAME) { 71412152Sphk if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 71512131Sphk indx++; 71612429Sphk if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK) 71712429Sphk req->lock = 0; 71812131Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 71912131Sphk if ((*oidpp)->oid_handler) 72012131Sphk goto found; 72112243Sphk if (indx == namelen) 72212131Sphk return ENOENT; 72312131Sphk lsp = (struct linker_set*)(*oidpp)->oid_arg1; 72412131Sphk j = lsp->ls_length; 72512131Sphk oidpp = (struct sysctl_oid **)lsp->ls_items; 72612131Sphk } else { 72712243Sphk if (indx != namelen) 72812131Sphk return EISDIR; 72912131Sphk goto found; 73012131Sphk } 73112131Sphk } else { 73212131Sphk oidpp++; 73312131Sphk } 73412131Sphk } 73512260Sphk return ENOENT; 73612131Sphkfound: 73712131Sphk /* If writing isn't allowed */ 73812243Sphk if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR)) 73912131Sphk return (EPERM); 74012131Sphk 74112910Sphk /* Most likely only root can write */ 74212910Sphk if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) && 74312910Sphk req->newptr && req->p && 74412910Sphk (i = suser(req->p->p_ucred, &req->p->p_acflag))) 74512910Sphk return (i); 74612910Sphk 74712243Sphk if (!(*oidpp)->oid_handler) 74812131Sphk return EINVAL; 74912131Sphk 75012131Sphk if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 75112131Sphk i = ((*oidpp)->oid_handler) (*oidpp, 75212131Sphk name + indx, namelen - indx, 75312243Sphk req); 75412131Sphk } else { 75512131Sphk i = ((*oidpp)->oid_handler) (*oidpp, 75612131Sphk (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 75712243Sphk req); 75812131Sphk } 75912131Sphk return (i); 76012131Sphk} 76112131Sphk 76212221Sbde#ifndef _SYS_SYSPROTO_H_ 76312171Sphkstruct sysctl_args { 76412171Sphk int *name; 76512171Sphk u_int namelen; 76612171Sphk void *old; 76712171Sphk size_t *oldlenp; 76812171Sphk void *new; 76912171Sphk size_t newlen; 77012171Sphk}; 77112221Sbde#endif 77212171Sphk 77312131Sphkint 77430994Sphk__sysctl(struct proc *p, struct sysctl_args *uap) 7751541Srgrimes{ 77612260Sphk int error, i, j, name[CTL_MAXNAME]; 7771541Srgrimes 7781541Srgrimes if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 7791541Srgrimes return (EINVAL); 78011863Sphk 7813308Sphk error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 7823308Sphk if (error) 7831541Srgrimes return (error); 7841541Srgrimes 78512260Sphk error = userland_sysctl(p, name, uap->namelen, 78612171Sphk uap->old, uap->oldlenp, 0, 78712260Sphk uap->new, uap->newlen, &j); 78812260Sphk if (error && error != ENOMEM) 78912260Sphk return (error); 79012260Sphk if (uap->oldlenp) { 79112260Sphk i = copyout(&j, uap->oldlenp, sizeof(j)); 79212260Sphk if (i) 79312260Sphk return (i); 79412260Sphk } 79512260Sphk return (error); 79612171Sphk} 79712171Sphk 79812171Sphk/* 79912171Sphk * This is used from various compatibility syscalls too. That's why name 80012171Sphk * must be in kernel space. 80112171Sphk */ 80212171Sphkint 80312171Sphkuserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval) 80412171Sphk{ 80512429Sphk int error = 0; 80616159Sphk struct sysctl_req req, req2; 80712171Sphk 80812243Sphk bzero(&req, sizeof req); 80912243Sphk 81012285Sphk req.p = p; 81112285Sphk 81212171Sphk if (oldlenp) { 81312171Sphk if (inkernel) { 81412243Sphk req.oldlen = *oldlenp; 81512171Sphk } else { 81612260Sphk error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); 81712171Sphk if (error) 81812171Sphk return (error); 81912171Sphk } 82012171Sphk } 82112171Sphk 82212243Sphk if (old) { 82312243Sphk if (!useracc(old, req.oldlen, B_WRITE)) 82412243Sphk return (EFAULT); 82512243Sphk req.oldptr= old; 82612243Sphk } 82712131Sphk 82812171Sphk if (newlen) { 82912243Sphk if (!useracc(new, req.newlen, B_READ)) 83012243Sphk return (EFAULT); 83112243Sphk req.newlen = newlen; 83212243Sphk req.newptr = new; 83311863Sphk } 83412131Sphk 83512243Sphk req.oldfunc = sysctl_old_user; 83612243Sphk req.newfunc = sysctl_new_user; 83712429Sphk req.lock = 1; 83811863Sphk 83912429Sphk /* XXX this should probably be done in a general way */ 84012429Sphk while (memlock.sl_lock) { 84112429Sphk memlock.sl_want = 1; 84212429Sphk (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 84312429Sphk memlock.sl_locked++; 84412429Sphk } 84512429Sphk memlock.sl_lock = 1; 84612429Sphk 84716159Sphk do { 84816159Sphk req2 = req; 84916159Sphk error = sysctl_root(0, name, namelen, &req2); 85016159Sphk } while (error == EAGAIN); 85112243Sphk 85216159Sphk req = req2; 85312429Sphk if (req.lock == 2) 85412429Sphk vsunlock(req.oldptr, req.oldlen, B_WRITE); 85512429Sphk 85612429Sphk memlock.sl_lock = 0; 85712429Sphk 85812429Sphk if (memlock.sl_want) { 85912429Sphk memlock.sl_want = 0; 86012429Sphk wakeup((caddr_t)&memlock); 86112429Sphk } 86212429Sphk 86312260Sphk if (error && error != ENOMEM) 86412260Sphk return (error); 86512260Sphk 86612260Sphk if (retval) { 86712260Sphk if (req.oldptr && req.oldidx > req.oldlen) 86812243Sphk *retval = req.oldlen; 86912260Sphk else 87012260Sphk *retval = req.oldidx; 87111863Sphk } 87212260Sphk return (error); 8731541Srgrimes} 8741541Srgrimes 8751541Srgrimes#ifdef COMPAT_43 8761541Srgrimes#include <sys/socket.h> 87715103Sphk#include <vm/vm_param.h> 87815103Sphk 8791541Srgrimes#define KINFO_PROC (0<<8) 8801541Srgrimes#define KINFO_RT (1<<8) 8811541Srgrimes#define KINFO_VNODE (2<<8) 8821541Srgrimes#define KINFO_FILE (3<<8) 8831541Srgrimes#define KINFO_METER (4<<8) 8841541Srgrimes#define KINFO_LOADAVG (5<<8) 8851541Srgrimes#define KINFO_CLOCKRATE (6<<8) 8861541Srgrimes 8879455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 8889455Speter#define KINFO_BSDI_SYSINFO (101<<8) 8899455Speter 8909455Speter/* 8919455Speter * XXX this is bloat, but I hope it's better here than on the potentially 8929455Speter * limited kernel stack... -Peter 8939455Speter */ 8949455Speter 89512819Sphkstatic struct { 8969455Speter int bsdi_machine; /* "i386" on BSD/386 */ 8979455Speter/* ^^^ this is an offset to the string, relative to the struct start */ 8989455Speter char *pad0; 8999455Speter long pad1; 9009455Speter long pad2; 9019455Speter long pad3; 9029455Speter u_long pad4; 9039455Speter u_long pad5; 9049455Speter u_long pad6; 9059455Speter 9069455Speter int bsdi_ostype; /* "BSD/386" on BSD/386 */ 9079455Speter int bsdi_osrelease; /* "1.1" on BSD/386 */ 9089455Speter long pad7; 9099455Speter long pad8; 9109455Speter char *pad9; 9119455Speter 9129455Speter long pad10; 9139455Speter long pad11; 9149455Speter int pad12; 9159455Speter long pad13; 9169455Speter quad_t pad14; 9179455Speter long pad15; 9189455Speter 9199455Speter struct timeval pad16; 9209455Speter /* we dont set this, because BSDI's uname used gethostname() instead */ 9219455Speter int bsdi_hostname; /* hostname on BSD/386 */ 9229455Speter 9239455Speter /* the actual string data is appended here */ 9249455Speter 9259455Speter} bsdi_si; 9269455Speter/* 9279455Speter * this data is appended to the end of the bsdi_si structure during copyout. 9289455Speter * The "char *" offsets are relative to the base of the bsdi_si struct. 9299455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 9309455Speter * should not exceed the length of the buffer here... (or else!! :-) 9319455Speter */ 93212819Sphkstatic char bsdi_strings[80]; /* It had better be less than this! */ 9339455Speter 93412221Sbde#ifndef _SYS_SYSPROTO_H_ 9351541Srgrimesstruct getkerninfo_args { 9361541Srgrimes int op; 9371541Srgrimes char *where; 9381541Srgrimes int *size; 9391541Srgrimes int arg; 9401541Srgrimes}; 94112221Sbde#endif 9421541Srgrimes 9431549Srgrimesint 94430994Sphkogetkerninfo(struct proc *p, struct getkerninfo_args *uap) 9451541Srgrimes{ 94612171Sphk int error, name[6]; 9471541Srgrimes u_int size; 9481541Srgrimes 9491541Srgrimes switch (uap->op & 0xff00) { 9501541Srgrimes 9511541Srgrimes case KINFO_RT: 95212171Sphk name[0] = CTL_NET; 95312171Sphk name[1] = PF_ROUTE; 95412171Sphk name[2] = 0; 95512171Sphk name[3] = (uap->op & 0xff0000) >> 16; 95612171Sphk name[4] = uap->op & 0xff; 95712171Sphk name[5] = uap->arg; 95812171Sphk error = userland_sysctl(p, name, 6, uap->where, uap->size, 95912429Sphk 0, 0, 0, &size); 9601541Srgrimes break; 9611541Srgrimes 9621541Srgrimes case KINFO_VNODE: 96312171Sphk name[0] = CTL_KERN; 96412171Sphk name[1] = KERN_VNODE; 96512171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 96612429Sphk 0, 0, 0, &size); 9671541Srgrimes break; 9681541Srgrimes 9691541Srgrimes case KINFO_PROC: 97012171Sphk name[0] = CTL_KERN; 97112171Sphk name[1] = KERN_PROC; 97212171Sphk name[2] = uap->op & 0xff; 97312171Sphk name[3] = uap->arg; 97412171Sphk error = userland_sysctl(p, name, 4, uap->where, uap->size, 97512429Sphk 0, 0, 0, &size); 9761541Srgrimes break; 9771541Srgrimes 9781541Srgrimes case KINFO_FILE: 97912171Sphk name[0] = CTL_KERN; 98012171Sphk name[1] = KERN_FILE; 98112171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 98212429Sphk 0, 0, 0, &size); 9831541Srgrimes break; 9841541Srgrimes 9851541Srgrimes case KINFO_METER: 98612171Sphk name[0] = CTL_VM; 98712171Sphk name[1] = VM_METER; 98812171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 98912429Sphk 0, 0, 0, &size); 9901541Srgrimes break; 9911541Srgrimes 9921541Srgrimes case KINFO_LOADAVG: 99312171Sphk name[0] = CTL_VM; 99412171Sphk name[1] = VM_LOADAVG; 99512171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 99612429Sphk 0, 0, 0, &size); 9971541Srgrimes break; 9981541Srgrimes 9991541Srgrimes case KINFO_CLOCKRATE: 100012171Sphk name[0] = CTL_KERN; 100112171Sphk name[1] = KERN_CLOCKRATE; 100212171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 100312429Sphk 0, 0, 0, &size); 10041541Srgrimes break; 10051541Srgrimes 10069455Speter case KINFO_BSDI_SYSINFO: { 10079455Speter /* 10089455Speter * this is pretty crude, but it's just enough for uname() 10099455Speter * from BSDI's 1.x libc to work. 10109455Speter * 10119455Speter * In particular, it doesn't return the same results when 10129455Speter * the supplied buffer is too small. BSDI's version apparently 10139455Speter * will return the amount copied, and set the *size to how 10149455Speter * much was needed. The emulation framework here isn't capable 10159455Speter * of that, so we just set both to the amount copied. 10169455Speter * BSDI's 2.x product apparently fails with ENOMEM in this 10179455Speter * scenario. 10189455Speter */ 10199455Speter 10209455Speter u_int needed; 10219455Speter u_int left; 10229455Speter char *s; 10239455Speter 10249455Speter bzero((char *)&bsdi_si, sizeof(bsdi_si)); 10259455Speter bzero(bsdi_strings, sizeof(bsdi_strings)); 10269455Speter 10279455Speter s = bsdi_strings; 10289455Speter 10299455Speter bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 10309455Speter strcpy(s, ostype); 10319455Speter s += strlen(s) + 1; 10329455Speter 10339455Speter bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 10349455Speter strcpy(s, osrelease); 10359455Speter s += strlen(s) + 1; 10369455Speter 10379455Speter bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 10389455Speter strcpy(s, machine); 10399455Speter s += strlen(s) + 1; 10409455Speter 10419455Speter needed = sizeof(bsdi_si) + (s - bsdi_strings); 10429455Speter 10439455Speter if (uap->where == NULL) { 10449455Speter /* process is asking how much buffer to supply.. */ 10459455Speter size = needed; 10469455Speter error = 0; 10479455Speter break; 10489455Speter } 10499455Speter 10509455Speter 10519455Speter /* if too much buffer supplied, trim it down */ 10529455Speter if (size > needed) 10539455Speter size = needed; 10549455Speter 10559455Speter /* how much of the buffer is remaining */ 10569455Speter left = size; 10579455Speter 10589455Speter if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 10599455Speter break; 10609455Speter 10619455Speter /* is there any point in continuing? */ 10629455Speter if (left > sizeof(bsdi_si)) { 10639455Speter left -= sizeof(bsdi_si); 10649455Speter error = copyout(&bsdi_strings, 10659455Speter uap->where + sizeof(bsdi_si), left); 10669455Speter } 10679455Speter break; 10689455Speter } 10699455Speter 10701541Srgrimes default: 10711541Srgrimes return (EOPNOTSUPP); 10721541Srgrimes } 10731541Srgrimes if (error) 10741541Srgrimes return (error); 107530994Sphk p->p_retval[0] = size; 10761541Srgrimes if (uap->size) 10771541Srgrimes error = copyout((caddr_t)&size, (caddr_t)uap->size, 10781541Srgrimes sizeof(size)); 10791541Srgrimes return (error); 10801541Srgrimes} 10811541Srgrimes#endif /* COMPAT_43 */ 1082