kern_sysctl.c revision 44972
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 4044972Sphk * $Id: kern_sysctl.c,v 1.84 1999/02/16 10:49:48 dfr 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 6944078Sdfrstruct sysctl_oid_list sysctl__children; /* root list */ 7012152Sphk 7112623Sphk/* 7212623Sphk * Initialization of the MIB tree. 7312623Sphk * 7444078Sdfr * Order by number in each list. 7512623Sphk */ 7612429Sphk 7744078Sdfrvoid sysctl_register_oid(struct sysctl_oid *oidp) 7812152Sphk{ 7944078Sdfr struct sysctl_oid_list *parent = oidp->oid_parent; 8044078Sdfr struct sysctl_oid *p; 8144078Sdfr struct sysctl_oid *q; 8244078Sdfr int n; 8312197Sbde 8444078Sdfr /* 8544078Sdfr * If this oid has a number OID_AUTO, give it a number which 8644078Sdfr * is greater than any current oid. Make sure it is at least 8744078Sdfr * 100 to leave space for pre-assigned oid numbers. 8844078Sdfr */ 8944078Sdfr if (oidp->oid_number == OID_AUTO) { 9044078Sdfr /* First, find the highest oid in the parent list >99 */ 9144078Sdfr n = 99; 9244078Sdfr SLIST_FOREACH(p, parent, oid_link) { 9344078Sdfr if (p->oid_number > n) 9444078Sdfr n = p->oid_number; 9544078Sdfr } 9644078Sdfr oidp->oid_number = n + 1; 9744078Sdfr } 9844078Sdfr 9944078Sdfr /* 10044078Sdfr * Insert the oid into the parent's list in order. 10144078Sdfr */ 10244078Sdfr q = NULL; 10344078Sdfr SLIST_FOREACH(p, parent, oid_link) { 10444078Sdfr if (oidp->oid_number < p->oid_number) 10544078Sdfr break; 10644078Sdfr q = p; 10744078Sdfr } 10844078Sdfr if (q) 10944078Sdfr SLIST_INSERT_AFTER(q, oidp, oid_link); 11044078Sdfr else 11144078Sdfr SLIST_INSERT_HEAD(parent, oidp, oid_link); 11212152Sphk} 11312131Sphk 11444078Sdfrvoid sysctl_unregister_oid(struct sysctl_oid *oidp) 11512152Sphk{ 11644078Sdfr SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link); 11744078Sdfr} 11812152Sphk 11944078Sdfr/* 12044078Sdfr * Bulk-register all the oids in a linker_set. 12144078Sdfr */ 12244078Sdfrvoid sysctl_register_set(struct linker_set *lsp) 12344078Sdfr{ 12444078Sdfr int count = lsp->ls_length; 12544078Sdfr int i; 12644078Sdfr for (i = 0; i < count; i++) 12744078Sdfr sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]); 12844078Sdfr} 12912623Sphk 13044078Sdfrvoid sysctl_unregister_set(struct linker_set *lsp) 13144078Sdfr{ 13244078Sdfr int count = lsp->ls_length; 13344078Sdfr int i; 13444078Sdfr for (i = 0; i < count; i++) 13544078Sdfr sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]); 13612152Sphk} 13712152Sphk 13844078Sdfr/* 13944078Sdfr * Register the kernel's oids on startup. 14044078Sdfr */ 14144078Sdfrextern struct linker_set sysctl_set; 14212152Sphk 14344078Sdfrstatic void sysctl_register_all(void *arg) 14438869Sbde{ 14544078Sdfr sysctl_register_set(&sysctl_set); 14638869Sbde} 14738869Sbde 14844078SdfrSYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0); 14944078Sdfr 15012623Sphk/* 15112623Sphk * "Staff-functions" 15212623Sphk * 15312650Sphk * These functions implement a presently undocumented interface 15412650Sphk * used by the sysctl program to walk the tree, and get the type 15512650Sphk * so it can print the value. 15612650Sphk * This interface is under work and consideration, and should probably 15712650Sphk * be killed with a big axe by the first person who can find the time. 15812650Sphk * (be aware though, that the proper interface isn't as obvious as it 15912650Sphk * may seem, there are various conflicting requirements. 16012650Sphk * 16112623Sphk * {0,0} printf the entire MIB-tree. 16212623Sphk * {0,1,...} return the name of the "..." OID. 16342467Sphk * {0,2,...} return the next OID. 16412623Sphk * {0,3} return the OID of the name in "new" 16512650Sphk * {0,4,...} return the kind & format info for the "..." OID. 16612623Sphk */ 16712623Sphk 16812152Sphkstatic void 16944078Sdfrsysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i) 17012152Sphk{ 17144078Sdfr int k; 17244078Sdfr struct sysctl_oid *oidp; 17312152Sphk 17444078Sdfr SLIST_FOREACH(oidp, l, oid_link) { 17512152Sphk 17612152Sphk for (k=0; k<i; k++) 17712152Sphk printf(" "); 17812152Sphk 17944078Sdfr printf("%d %s ", oidp->oid_number, oidp->oid_name); 18012152Sphk 18112152Sphk printf("%c%c", 18244078Sdfr oidp->oid_kind & CTLFLAG_RD ? 'R':' ', 18344078Sdfr oidp->oid_kind & CTLFLAG_WR ? 'W':' '); 18412152Sphk 18544078Sdfr if (oidp->oid_handler) 18615241Sphk printf(" *Handler"); 18715241Sphk 18844078Sdfr switch (oidp->oid_kind & CTLTYPE) { 18912243Sphk case CTLTYPE_NODE: 19015241Sphk printf(" Node\n"); 19144078Sdfr if (!oidp->oid_handler) { 19212152Sphk sysctl_sysctl_debug_dump_node( 19344078Sdfr oidp->oid_arg1, i+2); 19412152Sphk } 19512152Sphk break; 19612152Sphk case CTLTYPE_INT: printf(" Int\n"); break; 19712152Sphk case CTLTYPE_STRING: printf(" String\n"); break; 19812152Sphk case CTLTYPE_QUAD: printf(" Quad\n"); break; 19912152Sphk case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 20012152Sphk default: printf("\n"); 20112152Sphk } 20212152Sphk 20312152Sphk } 20412152Sphk} 20512152Sphk 20612152Sphkstatic int 20712152Sphksysctl_sysctl_debug SYSCTL_HANDLER_ARGS 20812152Sphk{ 20944078Sdfr sysctl_sysctl_debug_dump_node(&sysctl__children, 0); 21012152Sphk return ENOENT; 21112152Sphk} 21212152Sphk 21312152SphkSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 21412623Sphk 0, 0, sysctl_sysctl_debug, "-", ""); 21512152Sphk 21612623Sphkstatic int 21712623Sphksysctl_sysctl_name SYSCTL_HANDLER_ARGS 21812623Sphk{ 21912623Sphk int *name = (int *) arg1; 22012623Sphk u_int namelen = arg2; 22144078Sdfr int error = 0; 22244078Sdfr struct sysctl_oid *oid; 22344972Sphk struct sysctl_oid_list *lsp = &sysctl__children, *lsp2; 22412623Sphk char buf[10]; 22512131Sphk 22612623Sphk while (namelen) { 22712623Sphk if (!lsp) { 22841514Sarchie snprintf(buf,sizeof(buf),"%d",*name); 22912623Sphk if (req->oldidx) 23012623Sphk error = SYSCTL_OUT(req, ".", 1); 23112623Sphk if (!error) 23212623Sphk error = SYSCTL_OUT(req, buf, strlen(buf)); 23312623Sphk if (error) 23412623Sphk return (error); 23512623Sphk namelen--; 23612623Sphk name++; 23712623Sphk continue; 23812623Sphk } 23944972Sphk lsp2 = 0; 24044078Sdfr SLIST_FOREACH(oid, lsp, oid_link) { 24144078Sdfr if (oid->oid_number != *name) 24212623Sphk continue; 24312131Sphk 24412623Sphk if (req->oldidx) 24512623Sphk error = SYSCTL_OUT(req, ".", 1); 24612623Sphk if (!error) 24744078Sdfr error = SYSCTL_OUT(req, oid->oid_name, 24844078Sdfr strlen(oid->oid_name)); 24912623Sphk if (error) 25012623Sphk return (error); 25112623Sphk 25212623Sphk namelen--; 25312623Sphk name++; 25412623Sphk 25544972Sphk if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) 25612623Sphk break; 25712623Sphk 25844078Sdfr if (oid->oid_handler) 25912623Sphk break; 26012623Sphk 26144972Sphk lsp2 = (struct sysctl_oid_list *)oid->oid_arg1; 26212623Sphk break; 26312623Sphk } 26444972Sphk lsp = lsp2; 26512623Sphk } 26612623Sphk return (SYSCTL_OUT(req, "", 1)); 26712623Sphk} 26812623Sphk 26912623SphkSYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); 27012623Sphk 27112623Sphkstatic int 27244078Sdfrsysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen, 27344078Sdfr int *next, int *len, int level, struct sysctl_oid **oidpp) 27412623Sphk{ 27544078Sdfr struct sysctl_oid *oidp; 27612623Sphk 27712623Sphk *len = level; 27844078Sdfr SLIST_FOREACH(oidp, lsp, oid_link) { 27944078Sdfr *next = oidp->oid_number; 28044078Sdfr *oidpp = oidp; 28112623Sphk 28212623Sphk if (!namelen) { 28344078Sdfr if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 28412623Sphk return 0; 28544078Sdfr if (oidp->oid_handler) 28612623Sphk /* We really should call the handler here...*/ 28712623Sphk return 0; 28844078Sdfr lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 28915241Sphk if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1, 29044078Sdfr len, level+1, oidpp)) 29115241Sphk return 0; 29215241Sphk goto next; 29312623Sphk } 29412623Sphk 29544078Sdfr if (oidp->oid_number < *name) 29612623Sphk continue; 29712623Sphk 29844078Sdfr if (oidp->oid_number > *name) { 29944078Sdfr if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 30012623Sphk return 0; 30144078Sdfr if (oidp->oid_handler) 30212623Sphk return 0; 30344078Sdfr lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 30412623Sphk if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, 30544078Sdfr next+1, len, level+1, oidpp)) 30612623Sphk return (0); 30715241Sphk goto next; 30812623Sphk } 30944078Sdfr if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 31012623Sphk continue; 31112623Sphk 31244078Sdfr if (oidp->oid_handler) 31312623Sphk continue; 31412623Sphk 31544078Sdfr lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 31612623Sphk if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1, 31744078Sdfr len, level+1, oidpp)) 31812623Sphk return (0); 31915241Sphk next: 32012623Sphk namelen = 1; 32112623Sphk *len = level; 32212623Sphk } 32312623Sphk return 1; 32412623Sphk} 32512623Sphk 32612623Sphkstatic int 32712623Sphksysctl_sysctl_next SYSCTL_HANDLER_ARGS 32812623Sphk{ 32912623Sphk int *name = (int *) arg1; 33012623Sphk u_int namelen = arg2; 33112623Sphk int i, j, error; 33212623Sphk struct sysctl_oid *oid; 33344078Sdfr struct sysctl_oid_list *lsp = &sysctl__children; 33412623Sphk int newoid[CTL_MAXNAME]; 33512623Sphk 33612623Sphk i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid); 33712623Sphk if (i) 33812623Sphk return ENOENT; 33912650Sphk error = SYSCTL_OUT(req, newoid, j * sizeof (int)); 34012623Sphk return (error); 34112623Sphk} 34212623Sphk 34312623SphkSYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, ""); 34412623Sphk 34512623Sphkstatic int 34644078Sdfrname2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp) 34712623Sphk{ 34844078Sdfr int i; 34944078Sdfr struct sysctl_oid *oidp; 35044078Sdfr struct sysctl_oid_list *lsp = &sysctl__children; 35112623Sphk char *p; 35212623Sphk 35312623Sphk if (!*name) 35412623Sphk return ENOENT; 35512623Sphk 35612623Sphk p = name + strlen(name) - 1 ; 35712623Sphk if (*p == '.') 35812623Sphk *p = '\0'; 35912623Sphk 36012623Sphk *len = 0; 36112623Sphk 36212623Sphk for (p = name; *p && *p != '.'; p++) 36312623Sphk ; 36412623Sphk i = *p; 36512623Sphk if (i == '.') 36612623Sphk *p = '\0'; 36712623Sphk 36844078Sdfr oidp = SLIST_FIRST(lsp); 36912623Sphk 37044078Sdfr while (oidp && *len < CTL_MAXNAME) { 37144078Sdfr if (strcmp(name, oidp->oid_name)) { 37244078Sdfr oidp = SLIST_NEXT(oidp, oid_link); 37312623Sphk continue; 37412623Sphk } 37544078Sdfr *oid++ = oidp->oid_number; 37612623Sphk (*len)++; 37712623Sphk 37812623Sphk if (!i) { 37944078Sdfr if (oidpp) 38044078Sdfr *oidpp = oidp; 38112623Sphk return (0); 38212623Sphk } 38312623Sphk 38444078Sdfr if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 38512623Sphk break; 38612623Sphk 38744078Sdfr if (oidp->oid_handler) 38812623Sphk break; 38912623Sphk 39044078Sdfr lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 39144078Sdfr oidp = SLIST_FIRST(lsp); 39212623Sphk name = p+1; 39312623Sphk for (p = name; *p && *p != '.'; p++) 39412623Sphk ; 39512623Sphk i = *p; 39612623Sphk if (i == '.') 39712623Sphk *p = '\0'; 39812623Sphk } 39912623Sphk return ENOENT; 40012623Sphk} 40112623Sphk 40212623Sphkstatic int 40312623Sphksysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS 40412623Sphk{ 40512623Sphk char *p; 40612623Sphk int error, oid[CTL_MAXNAME], len; 40712623Sphk struct sysctl_oid *op = 0; 40812623Sphk 40912623Sphk if (!req->newlen) 41012623Sphk return ENOENT; 41112623Sphk 41212623Sphk p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK); 41312623Sphk 41412623Sphk error = SYSCTL_IN(req, p, req->newlen); 41512623Sphk if (error) { 41612623Sphk free(p, M_SYSCTL); 41712623Sphk return (error); 41812623Sphk } 41912623Sphk 42012623Sphk p [req->newlen] = '\0'; 42112623Sphk 42212623Sphk error = name2oid(p, oid, &len, &op); 42312623Sphk 42412623Sphk free(p, M_SYSCTL); 42512623Sphk 42612623Sphk if (error) 42712623Sphk return (error); 42812623Sphk 42912650Sphk error = SYSCTL_OUT(req, oid, len * sizeof *oid); 43012623Sphk return (error); 43112623Sphk} 43212623Sphk 43312910SphkSYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 43412623Sphk sysctl_sysctl_name2oid, "I", ""); 43512623Sphk 43612623Sphkstatic int 43712623Sphksysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS 43812623Sphk{ 43912650Sphk int *name = (int *) arg1, error; 44012623Sphk u_int namelen = arg2; 44144078Sdfr int indx; 44244078Sdfr struct sysctl_oid *oid; 44344078Sdfr struct sysctl_oid_list *lsp = &sysctl__children; 44412623Sphk 44544078Sdfr oid = SLIST_FIRST(lsp); 44612623Sphk 44712623Sphk indx = 0; 44844078Sdfr while (oid && indx < CTL_MAXNAME) { 44944078Sdfr if (oid->oid_number == name[indx]) { 45012623Sphk indx++; 45144078Sdfr if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 45244078Sdfr if (oid->oid_handler) 45312623Sphk goto found; 45412623Sphk if (indx == namelen) 45512650Sphk goto found; 45644078Sdfr lsp = (struct sysctl_oid_list *)oid->oid_arg1; 45744078Sdfr oid = SLIST_FIRST(lsp); 45812623Sphk } else { 45912623Sphk if (indx != namelen) 46012623Sphk return EISDIR; 46112623Sphk goto found; 46212623Sphk } 46312623Sphk } else { 46444078Sdfr oid = SLIST_NEXT(oid, oid_link); 46512623Sphk } 46612623Sphk } 46712623Sphk return ENOENT; 46812623Sphkfound: 46944078Sdfr if (!oid->oid_fmt) 47012623Sphk return ENOENT; 47112650Sphk error = SYSCTL_OUT(req, 47244078Sdfr &oid->oid_kind, sizeof(oid->oid_kind)); 47312650Sphk if (!error) 47444078Sdfr error = SYSCTL_OUT(req, oid->oid_fmt, 47544078Sdfr strlen(oid->oid_fmt)+1); 47612650Sphk return (error); 47712623Sphk} 47812623Sphk 47942467Sphk 48012623SphkSYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, ""); 48112623Sphk 48212243Sphk/* 48312623Sphk * Default "handler" functions. 48412623Sphk */ 48512623Sphk 48612623Sphk/* 48742095Sdfr * Handle an int, signed or unsigned. 48812243Sphk * Two cases: 48912243Sphk * a variable: point arg1 at it. 49012243Sphk * a constant: pass it in arg2. 49112243Sphk */ 49212243Sphk 49311865Sphkint 49411865Sphksysctl_handle_int SYSCTL_HANDLER_ARGS 49511863Sphk{ 49612243Sphk int error = 0; 49711863Sphk 49812243Sphk if (arg1) 49912243Sphk error = SYSCTL_OUT(req, arg1, sizeof(int)); 50020506Sbde else 50112243Sphk error = SYSCTL_OUT(req, &arg2, sizeof(int)); 50211863Sphk 50312243Sphk if (error || !req->newptr) 50412243Sphk return (error); 50511863Sphk 50612243Sphk if (!arg1) 50712243Sphk error = EPERM; 50812243Sphk else 50912243Sphk error = SYSCTL_IN(req, arg1, sizeof(int)); 51012243Sphk return (error); 51111863Sphk} 51211863Sphk 51312243Sphk/* 51442095Sdfr * Handle a long, signed or unsigned. 51538517Sdfr * Two cases: 51638517Sdfr * a variable: point arg1 at it. 51738517Sdfr * a constant: pass it in arg2. 51838517Sdfr */ 51938517Sdfr 52038517Sdfrint 52138517Sdfrsysctl_handle_long SYSCTL_HANDLER_ARGS 52238517Sdfr{ 52338517Sdfr int error = 0; 52438517Sdfr 52542095Sdfr error = SYSCTL_OUT(req, arg1, sizeof(long)); 52638517Sdfr 52738517Sdfr if (error || !req->newptr) 52838517Sdfr return (error); 52938517Sdfr 53038517Sdfr if (!arg1) 53138517Sdfr error = EPERM; 53238517Sdfr else 53338517Sdfr error = SYSCTL_IN(req, arg1, sizeof(long)); 53438517Sdfr return (error); 53538517Sdfr} 53638517Sdfr 53738517Sdfr/* 53812243Sphk * Handle our generic '\0' terminated 'C' string. 53912243Sphk * Two cases: 54012243Sphk * a variable string: point arg1 at it, arg2 is max length. 54112243Sphk * a constant string: point arg1 at it, arg2 is zero. 54212243Sphk */ 54312243Sphk 54411865Sphkint 54511865Sphksysctl_handle_string SYSCTL_HANDLER_ARGS 54611863Sphk{ 54712243Sphk int error=0; 54811863Sphk 54912297Sphk error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1); 55011863Sphk 55112260Sphk if (error || !req->newptr || !arg2) 55212243Sphk return (error); 55311863Sphk 55412243Sphk if ((req->newlen - req->newidx) > arg2) { 55512243Sphk error = E2BIG; 55612243Sphk } else { 55712243Sphk arg2 = (req->newlen - req->newidx); 55812243Sphk error = SYSCTL_IN(req, arg1, arg2); 55912243Sphk ((char *)arg1)[arg2] = '\0'; 56011863Sphk } 56112131Sphk 56212131Sphk return (error); 56311863Sphk} 56411863Sphk 56512243Sphk/* 56612243Sphk * Handle any kind of opaque data. 56712243Sphk * arg1 points to it, arg2 is the size. 56812243Sphk */ 56912243Sphk 57011865Sphkint 57111865Sphksysctl_handle_opaque SYSCTL_HANDLER_ARGS 57211863Sphk{ 57312243Sphk int error; 57412243Sphk 57512243Sphk error = SYSCTL_OUT(req, arg1, arg2); 57612243Sphk 57712243Sphk if (error || !req->newptr) 57812243Sphk return (error); 57912243Sphk 58012243Sphk error = SYSCTL_IN(req, arg1, arg2); 58112243Sphk 58212243Sphk return (error); 58312243Sphk} 58412243Sphk 58512260Sphk/* 58612260Sphk * Transfer functions to/from kernel space. 58712260Sphk * XXX: rather untested at this point 58812260Sphk */ 58912260Sphkstatic int 59038517Sdfrsysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) 59112243Sphk{ 59238517Sdfr size_t i = 0; 59312260Sphk 59412260Sphk if (req->oldptr) { 59538517Sdfr i = l; 59638517Sdfr if (i > req->oldlen - req->oldidx) 59738517Sdfr i = req->oldlen - req->oldidx; 59812260Sphk if (i > 0) 59917971Sbde bcopy(p, (char *)req->oldptr + req->oldidx, i); 60012243Sphk } 60112260Sphk req->oldidx += l; 60216282Snate if (req->oldptr && i != l) 60311863Sphk return (ENOMEM); 60412260Sphk return (0); 60512243Sphk} 60612243Sphk 60712260Sphkstatic int 60838517Sdfrsysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) 60912243Sphk{ 61012260Sphk if (!req->newptr) 61112260Sphk return 0; 61212260Sphk if (req->newlen - req->newidx < l) 61311863Sphk return (EINVAL); 61417971Sbde bcopy((char *)req->newptr + req->newidx, p, l); 61512243Sphk req->newidx += l; 61612131Sphk return (0); 61711863Sphk} 61811863Sphk 61916282Snateint 62038517Sdfrkernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval) 62116282Snate{ 62216282Snate int error = 0; 62316282Snate struct sysctl_req req; 62416282Snate 62516282Snate bzero(&req, sizeof req); 62616282Snate 62716282Snate req.p = p; 62816282Snate 62916282Snate if (oldlenp) { 63016282Snate req.oldlen = *oldlenp; 63116282Snate } 63216282Snate 63316282Snate if (old) { 63416282Snate req.oldptr= old; 63516282Snate } 63616282Snate 63716282Snate if (newlen) { 63816282Snate req.newlen = newlen; 63916282Snate req.newptr = new; 64016282Snate } 64116282Snate 64216282Snate req.oldfunc = sysctl_old_kernel; 64316282Snate req.newfunc = sysctl_new_kernel; 64416282Snate req.lock = 1; 64516282Snate 64616282Snate /* XXX this should probably be done in a general way */ 64716282Snate while (memlock.sl_lock) { 64816282Snate memlock.sl_want = 1; 64916282Snate (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 65016282Snate memlock.sl_locked++; 65116282Snate } 65216282Snate memlock.sl_lock = 1; 65316282Snate 65416282Snate error = sysctl_root(0, name, namelen, &req); 65516282Snate 65616282Snate if (req.lock == 2) 65716282Snate vsunlock(req.oldptr, req.oldlen, B_WRITE); 65816282Snate 65916282Snate memlock.sl_lock = 0; 66016282Snate 66116282Snate if (memlock.sl_want) { 66216282Snate memlock.sl_want = 0; 66316282Snate wakeup((caddr_t)&memlock); 66416282Snate } 66516282Snate 66616282Snate if (error && error != ENOMEM) 66716282Snate return (error); 66816282Snate 66916282Snate if (retval) { 67016282Snate if (req.oldptr && req.oldidx > req.oldlen) 67116282Snate *retval = req.oldlen; 67216282Snate else 67316282Snate *retval = req.oldidx; 67416282Snate } 67516282Snate return (error); 67616282Snate} 67716282Snate 67812260Sphk/* 67912260Sphk * Transfer function to/from user space. 68012260Sphk */ 68112260Sphkstatic int 68238517Sdfrsysctl_old_user(struct sysctl_req *req, const void *p, size_t l) 68312243Sphk{ 68438517Sdfr int error = 0; 68538517Sdfr size_t i = 0; 68612243Sphk 68712429Sphk if (req->lock == 1 && req->oldptr) { 68812429Sphk vslock(req->oldptr, req->oldlen); 68912429Sphk req->lock = 2; 69012429Sphk } 69112260Sphk if (req->oldptr) { 69238517Sdfr i = l; 69338517Sdfr if (i > req->oldlen - req->oldidx) 69438517Sdfr i = req->oldlen - req->oldidx; 69512260Sphk if (i > 0) 69617971Sbde error = copyout(p, (char *)req->oldptr + req->oldidx, 69717971Sbde i); 69812260Sphk } 69912260Sphk req->oldidx += l; 70012243Sphk if (error) 70112243Sphk return (error); 70212260Sphk if (req->oldptr && i < l) 70312243Sphk return (ENOMEM); 70412260Sphk return (0); 70512243Sphk} 70612243Sphk 70712260Sphkstatic int 70838517Sdfrsysctl_new_user(struct sysctl_req *req, void *p, size_t l) 70912243Sphk{ 71012285Sphk int error; 71112260Sphk 71212260Sphk if (!req->newptr) 71312260Sphk return 0; 71412260Sphk if (req->newlen - req->newidx < l) 71512243Sphk return (EINVAL); 71617971Sbde error = copyin((char *)req->newptr + req->newidx, p, l); 71712243Sphk req->newidx += l; 71812243Sphk return (error); 71912243Sphk} 72012243Sphk 7211541Srgrimes/* 72212131Sphk * Traverse our tree, and find the right node, execute whatever it points 72312131Sphk * at, and return the resulting error code. 72412131Sphk */ 72512131Sphk 7261541Srgrimesint 72712131Sphksysctl_root SYSCTL_HANDLER_ARGS 72812131Sphk{ 72912131Sphk int *name = (int *) arg1; 73012623Sphk u_int namelen = arg2; 73144078Sdfr int indx, i; 73244078Sdfr struct sysctl_oid *oid; 73344078Sdfr struct sysctl_oid_list *lsp = &sysctl__children; 73412131Sphk 73544078Sdfr oid = SLIST_FIRST(lsp); 73612131Sphk 73712131Sphk indx = 0; 73844078Sdfr while (oid && indx < CTL_MAXNAME) { 73944078Sdfr if (oid->oid_number == name[indx]) { 74012131Sphk indx++; 74144078Sdfr if (oid->oid_kind & CTLFLAG_NOLOCK) 74212429Sphk req->lock = 0; 74344078Sdfr if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 74444078Sdfr if (oid->oid_handler) 74512131Sphk goto found; 74612243Sphk if (indx == namelen) 74712131Sphk return ENOENT; 74844078Sdfr lsp = (struct sysctl_oid_list *)oid->oid_arg1; 74944078Sdfr oid = SLIST_FIRST(lsp); 75012131Sphk } else { 75112243Sphk if (indx != namelen) 75212131Sphk return EISDIR; 75312131Sphk goto found; 75412131Sphk } 75512131Sphk } else { 75644078Sdfr oid = SLIST_NEXT(oid, oid_link); 75712131Sphk } 75812131Sphk } 75912260Sphk return ENOENT; 76012131Sphkfound: 76112131Sphk /* If writing isn't allowed */ 76244078Sdfr if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) || 76344078Sdfr ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) 76412131Sphk return (EPERM); 76512131Sphk 76612910Sphk /* Most likely only root can write */ 76744078Sdfr if (!(oid->oid_kind & CTLFLAG_ANYBODY) && 76812910Sphk req->newptr && req->p && 76912910Sphk (i = suser(req->p->p_ucred, &req->p->p_acflag))) 77012910Sphk return (i); 77112910Sphk 77244078Sdfr if (!oid->oid_handler) 77312131Sphk return EINVAL; 77412131Sphk 77544078Sdfr if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 77644078Sdfr i = (oid->oid_handler) (oid, 77712131Sphk name + indx, namelen - indx, 77812243Sphk req); 77912131Sphk } else { 78044078Sdfr i = (oid->oid_handler) (oid, 78144078Sdfr oid->oid_arg1, oid->oid_arg2, 78212243Sphk req); 78312131Sphk } 78412131Sphk return (i); 78512131Sphk} 78612131Sphk 78712221Sbde#ifndef _SYS_SYSPROTO_H_ 78812171Sphkstruct sysctl_args { 78912171Sphk int *name; 79012171Sphk u_int namelen; 79112171Sphk void *old; 79212171Sphk size_t *oldlenp; 79312171Sphk void *new; 79412171Sphk size_t newlen; 79512171Sphk}; 79612221Sbde#endif 79712171Sphk 79812131Sphkint 79930994Sphk__sysctl(struct proc *p, struct sysctl_args *uap) 8001541Srgrimes{ 80138517Sdfr int error, i, name[CTL_MAXNAME]; 80238517Sdfr size_t j; 8031541Srgrimes 8041541Srgrimes if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 8051541Srgrimes return (EINVAL); 80611863Sphk 8073308Sphk error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 8083308Sphk if (error) 8091541Srgrimes return (error); 8101541Srgrimes 81112260Sphk error = userland_sysctl(p, name, uap->namelen, 81212171Sphk uap->old, uap->oldlenp, 0, 81312260Sphk uap->new, uap->newlen, &j); 81412260Sphk if (error && error != ENOMEM) 81512260Sphk return (error); 81612260Sphk if (uap->oldlenp) { 81712260Sphk i = copyout(&j, uap->oldlenp, sizeof(j)); 81812260Sphk if (i) 81912260Sphk return (i); 82012260Sphk } 82112260Sphk return (error); 82212171Sphk} 82312171Sphk 82412171Sphk/* 82512171Sphk * This is used from various compatibility syscalls too. That's why name 82612171Sphk * must be in kernel space. 82712171Sphk */ 82812171Sphkint 82938517Sdfruserland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval) 83012171Sphk{ 83112429Sphk int error = 0; 83216159Sphk struct sysctl_req req, req2; 83312171Sphk 83412243Sphk bzero(&req, sizeof req); 83512243Sphk 83612285Sphk req.p = p; 83712285Sphk 83812171Sphk if (oldlenp) { 83912171Sphk if (inkernel) { 84012243Sphk req.oldlen = *oldlenp; 84112171Sphk } else { 84212260Sphk error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); 84312171Sphk if (error) 84412171Sphk return (error); 84512171Sphk } 84612171Sphk } 84712171Sphk 84812243Sphk if (old) { 84912243Sphk if (!useracc(old, req.oldlen, B_WRITE)) 85012243Sphk return (EFAULT); 85112243Sphk req.oldptr= old; 85212243Sphk } 85312131Sphk 85412171Sphk if (newlen) { 85512243Sphk if (!useracc(new, req.newlen, B_READ)) 85612243Sphk return (EFAULT); 85712243Sphk req.newlen = newlen; 85812243Sphk req.newptr = new; 85911863Sphk } 86012131Sphk 86112243Sphk req.oldfunc = sysctl_old_user; 86212243Sphk req.newfunc = sysctl_new_user; 86312429Sphk req.lock = 1; 86411863Sphk 86512429Sphk /* XXX this should probably be done in a general way */ 86612429Sphk while (memlock.sl_lock) { 86712429Sphk memlock.sl_want = 1; 86812429Sphk (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 86912429Sphk memlock.sl_locked++; 87012429Sphk } 87112429Sphk memlock.sl_lock = 1; 87212429Sphk 87316159Sphk do { 87416159Sphk req2 = req; 87516159Sphk error = sysctl_root(0, name, namelen, &req2); 87616159Sphk } while (error == EAGAIN); 87712243Sphk 87816159Sphk req = req2; 87912429Sphk if (req.lock == 2) 88012429Sphk vsunlock(req.oldptr, req.oldlen, B_WRITE); 88112429Sphk 88212429Sphk memlock.sl_lock = 0; 88312429Sphk 88412429Sphk if (memlock.sl_want) { 88512429Sphk memlock.sl_want = 0; 88612429Sphk wakeup((caddr_t)&memlock); 88712429Sphk } 88812429Sphk 88912260Sphk if (error && error != ENOMEM) 89012260Sphk return (error); 89112260Sphk 89212260Sphk if (retval) { 89312260Sphk if (req.oldptr && req.oldidx > req.oldlen) 89412243Sphk *retval = req.oldlen; 89512260Sphk else 89612260Sphk *retval = req.oldidx; 89711863Sphk } 89812260Sphk return (error); 8991541Srgrimes} 9001541Srgrimes 9011541Srgrimes#ifdef COMPAT_43 9021541Srgrimes#include <sys/socket.h> 90315103Sphk#include <vm/vm_param.h> 90415103Sphk 9051541Srgrimes#define KINFO_PROC (0<<8) 9061541Srgrimes#define KINFO_RT (1<<8) 9071541Srgrimes#define KINFO_VNODE (2<<8) 9081541Srgrimes#define KINFO_FILE (3<<8) 9091541Srgrimes#define KINFO_METER (4<<8) 9101541Srgrimes#define KINFO_LOADAVG (5<<8) 9111541Srgrimes#define KINFO_CLOCKRATE (6<<8) 9121541Srgrimes 9139455Speter/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 9149455Speter#define KINFO_BSDI_SYSINFO (101<<8) 9159455Speter 9169455Speter/* 9179455Speter * XXX this is bloat, but I hope it's better here than on the potentially 9189455Speter * limited kernel stack... -Peter 9199455Speter */ 9209455Speter 92112819Sphkstatic struct { 9229455Speter int bsdi_machine; /* "i386" on BSD/386 */ 9239455Speter/* ^^^ this is an offset to the string, relative to the struct start */ 9249455Speter char *pad0; 9259455Speter long pad1; 9269455Speter long pad2; 9279455Speter long pad3; 9289455Speter u_long pad4; 9299455Speter u_long pad5; 9309455Speter u_long pad6; 9319455Speter 9329455Speter int bsdi_ostype; /* "BSD/386" on BSD/386 */ 9339455Speter int bsdi_osrelease; /* "1.1" on BSD/386 */ 9349455Speter long pad7; 9359455Speter long pad8; 9369455Speter char *pad9; 9379455Speter 9389455Speter long pad10; 9399455Speter long pad11; 9409455Speter int pad12; 9419455Speter long pad13; 9429455Speter quad_t pad14; 9439455Speter long pad15; 9449455Speter 9459455Speter struct timeval pad16; 9469455Speter /* we dont set this, because BSDI's uname used gethostname() instead */ 9479455Speter int bsdi_hostname; /* hostname on BSD/386 */ 9489455Speter 9499455Speter /* the actual string data is appended here */ 9509455Speter 9519455Speter} bsdi_si; 9529455Speter/* 9539455Speter * this data is appended to the end of the bsdi_si structure during copyout. 9549455Speter * The "char *" offsets are relative to the base of the bsdi_si struct. 9559455Speter * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 9569455Speter * should not exceed the length of the buffer here... (or else!! :-) 9579455Speter */ 95812819Sphkstatic char bsdi_strings[80]; /* It had better be less than this! */ 9599455Speter 96012221Sbde#ifndef _SYS_SYSPROTO_H_ 9611541Srgrimesstruct getkerninfo_args { 9621541Srgrimes int op; 9631541Srgrimes char *where; 96438864Sbde size_t *size; 9651541Srgrimes int arg; 9661541Srgrimes}; 96712221Sbde#endif 9681541Srgrimes 9691549Srgrimesint 97030994Sphkogetkerninfo(struct proc *p, struct getkerninfo_args *uap) 9711541Srgrimes{ 97212171Sphk int error, name[6]; 97338517Sdfr size_t size; 9741541Srgrimes 9751541Srgrimes switch (uap->op & 0xff00) { 9761541Srgrimes 9771541Srgrimes case KINFO_RT: 97812171Sphk name[0] = CTL_NET; 97912171Sphk name[1] = PF_ROUTE; 98012171Sphk name[2] = 0; 98112171Sphk name[3] = (uap->op & 0xff0000) >> 16; 98212171Sphk name[4] = uap->op & 0xff; 98312171Sphk name[5] = uap->arg; 98412171Sphk error = userland_sysctl(p, name, 6, uap->where, uap->size, 98512429Sphk 0, 0, 0, &size); 9861541Srgrimes break; 9871541Srgrimes 9881541Srgrimes case KINFO_VNODE: 98912171Sphk name[0] = CTL_KERN; 99012171Sphk name[1] = KERN_VNODE; 99112171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 99212429Sphk 0, 0, 0, &size); 9931541Srgrimes break; 9941541Srgrimes 9951541Srgrimes case KINFO_PROC: 99612171Sphk name[0] = CTL_KERN; 99712171Sphk name[1] = KERN_PROC; 99812171Sphk name[2] = uap->op & 0xff; 99912171Sphk name[3] = uap->arg; 100012171Sphk error = userland_sysctl(p, name, 4, uap->where, uap->size, 100112429Sphk 0, 0, 0, &size); 10021541Srgrimes break; 10031541Srgrimes 10041541Srgrimes case KINFO_FILE: 100512171Sphk name[0] = CTL_KERN; 100612171Sphk name[1] = KERN_FILE; 100712171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 100812429Sphk 0, 0, 0, &size); 10091541Srgrimes break; 10101541Srgrimes 10111541Srgrimes case KINFO_METER: 101212171Sphk name[0] = CTL_VM; 101312171Sphk name[1] = VM_METER; 101412171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 101512429Sphk 0, 0, 0, &size); 10161541Srgrimes break; 10171541Srgrimes 10181541Srgrimes case KINFO_LOADAVG: 101912171Sphk name[0] = CTL_VM; 102012171Sphk name[1] = VM_LOADAVG; 102112171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 102212429Sphk 0, 0, 0, &size); 10231541Srgrimes break; 10241541Srgrimes 10251541Srgrimes case KINFO_CLOCKRATE: 102612171Sphk name[0] = CTL_KERN; 102712171Sphk name[1] = KERN_CLOCKRATE; 102812171Sphk error = userland_sysctl(p, name, 2, uap->where, uap->size, 102912429Sphk 0, 0, 0, &size); 10301541Srgrimes break; 10311541Srgrimes 10329455Speter case KINFO_BSDI_SYSINFO: { 10339455Speter /* 10349455Speter * this is pretty crude, but it's just enough for uname() 10359455Speter * from BSDI's 1.x libc to work. 10369455Speter * 10379455Speter * In particular, it doesn't return the same results when 10389455Speter * the supplied buffer is too small. BSDI's version apparently 10399455Speter * will return the amount copied, and set the *size to how 10409455Speter * much was needed. The emulation framework here isn't capable 10419455Speter * of that, so we just set both to the amount copied. 10429455Speter * BSDI's 2.x product apparently fails with ENOMEM in this 10439455Speter * scenario. 10449455Speter */ 10459455Speter 10469455Speter u_int needed; 10479455Speter u_int left; 10489455Speter char *s; 10499455Speter 10509455Speter bzero((char *)&bsdi_si, sizeof(bsdi_si)); 10519455Speter bzero(bsdi_strings, sizeof(bsdi_strings)); 10529455Speter 10539455Speter s = bsdi_strings; 10549455Speter 10559455Speter bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 10569455Speter strcpy(s, ostype); 10579455Speter s += strlen(s) + 1; 10589455Speter 10599455Speter bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 10609455Speter strcpy(s, osrelease); 10619455Speter s += strlen(s) + 1; 10629455Speter 10639455Speter bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 10649455Speter strcpy(s, machine); 10659455Speter s += strlen(s) + 1; 10669455Speter 10679455Speter needed = sizeof(bsdi_si) + (s - bsdi_strings); 10689455Speter 10699455Speter if (uap->where == NULL) { 10709455Speter /* process is asking how much buffer to supply.. */ 10719455Speter size = needed; 10729455Speter error = 0; 10739455Speter break; 10749455Speter } 10759455Speter 10769455Speter 10779455Speter /* if too much buffer supplied, trim it down */ 10789455Speter if (size > needed) 10799455Speter size = needed; 10809455Speter 10819455Speter /* how much of the buffer is remaining */ 10829455Speter left = size; 10839455Speter 10849455Speter if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 10859455Speter break; 10869455Speter 10879455Speter /* is there any point in continuing? */ 10889455Speter if (left > sizeof(bsdi_si)) { 10899455Speter left -= sizeof(bsdi_si); 10909455Speter error = copyout(&bsdi_strings, 10919455Speter uap->where + sizeof(bsdi_si), left); 10929455Speter } 10939455Speter break; 10949455Speter } 10959455Speter 10961541Srgrimes default: 10971541Srgrimes return (EOPNOTSUPP); 10981541Srgrimes } 10991541Srgrimes if (error) 11001541Srgrimes return (error); 110130994Sphk p->p_retval[0] = size; 11021541Srgrimes if (uap->size) 11031541Srgrimes error = copyout((caddr_t)&size, (caddr_t)uap->size, 11041541Srgrimes sizeof(size)); 11051541Srgrimes return (error); 11061541Srgrimes} 11071541Srgrimes#endif /* COMPAT_43 */ 1108