The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_sysctl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1982, 1986, 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Mike Karels at Berkeley Software Design, Inc.
    7  *
    8  * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
    9  * project, to make these variables more userfriendly.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 4. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  *      @(#)kern_sysctl.c       8.4 (Berkeley) 4/14/94
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD: releng/8.0/sys/kern/kern_sysctl.c 196178 2009-08-13 10:31:02Z bz $");
   40 
   41 #include "opt_compat.h"
   42 #include "opt_ktrace.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/malloc.h>
   49 #include <sys/priv.h>
   50 #include <sys/proc.h>
   51 #include <sys/jail.h>
   52 #include <sys/lock.h>
   53 #include <sys/mutex.h>
   54 #include <sys/sx.h>
   55 #include <sys/sysproto.h>
   56 #include <sys/uio.h>
   57 #ifdef KTRACE
   58 #include <sys/ktrace.h>
   59 #endif
   60 
   61 #include <net/vnet.h>
   62 
   63 #include <security/mac/mac_framework.h>
   64 
   65 #include <vm/vm.h>
   66 #include <vm/vm_extern.h>
   67 
   68 static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
   69 static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
   70 static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
   71 
   72 /*
   73  * The sysctllock protects the MIB tree.  It also protects sysctl
   74  * contexts used with dynamic sysctls.  The sysctl_register_oid() and
   75  * sysctl_unregister_oid() routines require the sysctllock to already
   76  * be held, so the sysctl_lock() and sysctl_unlock() routines are
   77  * provided for the few places in the kernel which need to use that
   78  * API rather than using the dynamic API.  Use of the dynamic API is
   79  * strongly encouraged for most code.
   80  *
   81  * The sysctlmemlock is used to limit the amount of user memory wired for
   82  * sysctl requests.  This is implemented by serializing any userland
   83  * sysctl requests larger than a single page via an exclusive lock.
   84  */
   85 static struct sx sysctllock;
   86 static struct sx sysctlmemlock;
   87 
   88 #define SYSCTL_SLOCK()          sx_slock(&sysctllock)
   89 #define SYSCTL_SUNLOCK()        sx_sunlock(&sysctllock)
   90 #define SYSCTL_XLOCK()          sx_xlock(&sysctllock)
   91 #define SYSCTL_XUNLOCK()        sx_xunlock(&sysctllock)
   92 #define SYSCTL_ASSERT_XLOCKED() sx_assert(&sysctllock, SA_XLOCKED)
   93 #define SYSCTL_ASSERT_LOCKED()  sx_assert(&sysctllock, SA_LOCKED)
   94 #define SYSCTL_INIT()           sx_init(&sysctllock, "sysctl lock")
   95 
   96 static int sysctl_root(SYSCTL_HANDLER_ARGS);
   97 
   98 struct sysctl_oid_list sysctl__children; /* root list */
   99 
  100 static int      sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del,
  101                     int recurse);
  102 
  103 static struct sysctl_oid *
  104 sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
  105 {
  106         struct sysctl_oid *oidp;
  107 
  108         SYSCTL_ASSERT_LOCKED();
  109         SLIST_FOREACH(oidp, list, oid_link) {
  110                 if (strcmp(oidp->oid_name, name) == 0) {
  111                         return (oidp);
  112                 }
  113         }
  114         return (NULL);
  115 }
  116 
  117 /*
  118  * Initialization of the MIB tree.
  119  *
  120  * Order by number in each list.
  121  */
  122 void
  123 sysctl_lock(void)
  124 {
  125 
  126         SYSCTL_XLOCK();
  127 }
  128 
  129 void
  130 sysctl_unlock(void)
  131 {
  132 
  133         SYSCTL_XUNLOCK();
  134 }
  135 
  136 void
  137 sysctl_register_oid(struct sysctl_oid *oidp)
  138 {
  139         struct sysctl_oid_list *parent = oidp->oid_parent;
  140         struct sysctl_oid *p;
  141         struct sysctl_oid *q;
  142 
  143         /*
  144          * First check if another oid with the same name already
  145          * exists in the parent's list.
  146          */
  147         SYSCTL_ASSERT_XLOCKED();
  148         p = sysctl_find_oidname(oidp->oid_name, parent);
  149         if (p != NULL) {
  150                 if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  151                         p->oid_refcnt++;
  152                         return;
  153                 } else {
  154                         printf("can't re-use a leaf (%s)!\n", p->oid_name);
  155                         return;
  156                 }
  157         }
  158         /*
  159          * If this oid has a number OID_AUTO, give it a number which
  160          * is greater than any current oid.
  161          * NOTE: DO NOT change the starting value here, change it in
  162          * <sys/sysctl.h>, and make sure it is at least 256 to
  163          * accomodate e.g. net.inet.raw as a static sysctl node.
  164          */
  165         if (oidp->oid_number == OID_AUTO) {
  166                 static int newoid = CTL_AUTO_START;
  167 
  168                 oidp->oid_number = newoid++;
  169                 if (newoid == 0x7fffffff)
  170                         panic("out of oids");
  171         }
  172 #if 0
  173         else if (oidp->oid_number >= CTL_AUTO_START) {
  174                 /* do not panic; this happens when unregistering sysctl sets */
  175                 printf("static sysctl oid too high: %d", oidp->oid_number);
  176         }
  177 #endif
  178 
  179         /*
  180          * Insert the oid into the parent's list in order.
  181          */
  182         q = NULL;
  183         SLIST_FOREACH(p, parent, oid_link) {
  184                 if (oidp->oid_number < p->oid_number)
  185                         break;
  186                 q = p;
  187         }
  188         if (q)
  189                 SLIST_INSERT_AFTER(q, oidp, oid_link);
  190         else
  191                 SLIST_INSERT_HEAD(parent, oidp, oid_link);
  192 }
  193 
  194 void
  195 sysctl_unregister_oid(struct sysctl_oid *oidp)
  196 {
  197         struct sysctl_oid *p;
  198         int error;
  199 
  200         SYSCTL_ASSERT_XLOCKED();
  201         error = ENOENT;
  202         if (oidp->oid_number == OID_AUTO) {
  203                 error = EINVAL;
  204         } else {
  205                 SLIST_FOREACH(p, oidp->oid_parent, oid_link) {
  206                         if (p == oidp) {
  207                                 SLIST_REMOVE(oidp->oid_parent, oidp,
  208                                     sysctl_oid, oid_link);
  209                                 error = 0;
  210                                 break;
  211                         }
  212                 }
  213         }
  214 
  215         /* 
  216          * This can happen when a module fails to register and is
  217          * being unloaded afterwards.  It should not be a panic()
  218          * for normal use.
  219          */
  220         if (error)
  221                 printf("%s: failed to unregister sysctl\n", __func__);
  222 }
  223 
  224 /* Initialize a new context to keep track of dynamically added sysctls. */
  225 int
  226 sysctl_ctx_init(struct sysctl_ctx_list *c)
  227 {
  228 
  229         if (c == NULL) {
  230                 return (EINVAL);
  231         }
  232 
  233         /*
  234          * No locking here, the caller is responsible for not adding
  235          * new nodes to a context until after this function has
  236          * returned.
  237          */
  238         TAILQ_INIT(c);
  239         return (0);
  240 }
  241 
  242 /* Free the context, and destroy all dynamic oids registered in this context */
  243 int
  244 sysctl_ctx_free(struct sysctl_ctx_list *clist)
  245 {
  246         struct sysctl_ctx_entry *e, *e1;
  247         int error;
  248 
  249         error = 0;
  250         /*
  251          * First perform a "dry run" to check if it's ok to remove oids.
  252          * XXX FIXME
  253          * XXX This algorithm is a hack. But I don't know any
  254          * XXX better solution for now...
  255          */
  256         SYSCTL_XLOCK();
  257         TAILQ_FOREACH(e, clist, link) {
  258                 error = sysctl_remove_oid_locked(e->entry, 0, 0);
  259                 if (error)
  260                         break;
  261         }
  262         /*
  263          * Restore deregistered entries, either from the end,
  264          * or from the place where error occured.
  265          * e contains the entry that was not unregistered
  266          */
  267         if (error)
  268                 e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
  269         else
  270                 e1 = TAILQ_LAST(clist, sysctl_ctx_list);
  271         while (e1 != NULL) {
  272                 sysctl_register_oid(e1->entry);
  273                 e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
  274         }
  275         if (error) {
  276                 SYSCTL_XUNLOCK();
  277                 return(EBUSY);
  278         }
  279         /* Now really delete the entries */
  280         e = TAILQ_FIRST(clist);
  281         while (e != NULL) {
  282                 e1 = TAILQ_NEXT(e, link);
  283                 error = sysctl_remove_oid_locked(e->entry, 1, 0);
  284                 if (error)
  285                         panic("sysctl_remove_oid: corrupt tree, entry: %s",
  286                             e->entry->oid_name);
  287                 free(e, M_SYSCTLOID);
  288                 e = e1;
  289         }
  290         SYSCTL_XUNLOCK();
  291         return (error);
  292 }
  293 
  294 /* Add an entry to the context */
  295 struct sysctl_ctx_entry *
  296 sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
  297 {
  298         struct sysctl_ctx_entry *e;
  299 
  300         SYSCTL_ASSERT_XLOCKED();
  301         if (clist == NULL || oidp == NULL)
  302                 return(NULL);
  303         e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
  304         e->entry = oidp;
  305         TAILQ_INSERT_HEAD(clist, e, link);
  306         return (e);
  307 }
  308 
  309 /* Find an entry in the context */
  310 struct sysctl_ctx_entry *
  311 sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
  312 {
  313         struct sysctl_ctx_entry *e;
  314 
  315         SYSCTL_ASSERT_LOCKED();
  316         if (clist == NULL || oidp == NULL)
  317                 return(NULL);
  318         TAILQ_FOREACH(e, clist, link) {
  319                 if(e->entry == oidp)
  320                         return(e);
  321         }
  322         return (e);
  323 }
  324 
  325 /*
  326  * Delete an entry from the context.
  327  * NOTE: this function doesn't free oidp! You have to remove it
  328  * with sysctl_remove_oid().
  329  */
  330 int
  331 sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
  332 {
  333         struct sysctl_ctx_entry *e;
  334 
  335         if (clist == NULL || oidp == NULL)
  336                 return (EINVAL);
  337         SYSCTL_XLOCK();
  338         e = sysctl_ctx_entry_find(clist, oidp);
  339         if (e != NULL) {
  340                 TAILQ_REMOVE(clist, e, link);
  341                 SYSCTL_XUNLOCK();
  342                 free(e, M_SYSCTLOID);
  343                 return (0);
  344         } else {
  345                 SYSCTL_XUNLOCK();
  346                 return (ENOENT);
  347         }
  348 }
  349 
  350 /*
  351  * Remove dynamically created sysctl trees.
  352  * oidp - top of the tree to be removed
  353  * del - if 0 - just deregister, otherwise free up entries as well
  354  * recurse - if != 0 traverse the subtree to be deleted
  355  */
  356 int
  357 sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
  358 {
  359         int error;
  360 
  361         SYSCTL_XLOCK();
  362         error = sysctl_remove_oid_locked(oidp, del, recurse);
  363         SYSCTL_XUNLOCK();
  364         return (error);
  365 }
  366 
  367 static int
  368 sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse)
  369 {
  370         struct sysctl_oid *p;
  371         int error;
  372 
  373         SYSCTL_ASSERT_XLOCKED();
  374         if (oidp == NULL)
  375                 return(EINVAL);
  376         if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
  377                 printf("can't remove non-dynamic nodes!\n");
  378                 return (EINVAL);
  379         }
  380         /*
  381          * WARNING: normal method to do this should be through
  382          * sysctl_ctx_free(). Use recursing as the last resort
  383          * method to purge your sysctl tree of leftovers...
  384          * However, if some other code still references these nodes,
  385          * it will panic.
  386          */
  387         if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  388                 if (oidp->oid_refcnt == 1) {
  389                         SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
  390                                 if (!recurse)
  391                                         return (ENOTEMPTY);
  392                                 error = sysctl_remove_oid_locked(p, del,
  393                                     recurse);
  394                                 if (error)
  395                                         return (error);
  396                         }
  397                         if (del)
  398                                 free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
  399                 }
  400         }
  401         if (oidp->oid_refcnt > 1 ) {
  402                 oidp->oid_refcnt--;
  403         } else {
  404                 if (oidp->oid_refcnt == 0) {
  405                         printf("Warning: bad oid_refcnt=%u (%s)!\n",
  406                                 oidp->oid_refcnt, oidp->oid_name);
  407                         return (EINVAL);
  408                 }
  409                 sysctl_unregister_oid(oidp);
  410                 if (del) {
  411                         if (oidp->oid_descr)
  412                                 free((void *)(uintptr_t)(const void *)oidp->oid_descr, M_SYSCTLOID);
  413                         free((void *)(uintptr_t)(const void *)oidp->oid_name,
  414                              M_SYSCTLOID);
  415                         free(oidp, M_SYSCTLOID);
  416                 }
  417         }
  418         return (0);
  419 }
  420 
  421 /*
  422  * Create new sysctls at run time.
  423  * clist may point to a valid context initialized with sysctl_ctx_init().
  424  */
  425 struct sysctl_oid *
  426 sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
  427         int number, const char *name, int kind, void *arg1, int arg2,
  428         int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
  429 {
  430         struct sysctl_oid *oidp;
  431         ssize_t len;
  432         char *newname;
  433 
  434         /* You have to hook up somewhere.. */
  435         if (parent == NULL)
  436                 return(NULL);
  437         /* Check if the node already exists, otherwise create it */
  438         SYSCTL_XLOCK();
  439         oidp = sysctl_find_oidname(name, parent);
  440         if (oidp != NULL) {
  441                 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  442                         oidp->oid_refcnt++;
  443                         /* Update the context */
  444                         if (clist != NULL)
  445                                 sysctl_ctx_entry_add(clist, oidp);
  446                         SYSCTL_XUNLOCK();
  447                         return (oidp);
  448                 } else {
  449                         SYSCTL_XUNLOCK();
  450                         printf("can't re-use a leaf (%s)!\n", name);
  451                         return (NULL);
  452                 }
  453         }
  454         oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO);
  455         oidp->oid_parent = parent;
  456         SLIST_NEXT(oidp, oid_link) = NULL;
  457         oidp->oid_number = number;
  458         oidp->oid_refcnt = 1;
  459         len = strlen(name);
  460         newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
  461         bcopy(name, newname, len + 1);
  462         newname[len] = '\0';
  463         oidp->oid_name = newname;
  464         oidp->oid_handler = handler;
  465         oidp->oid_kind = CTLFLAG_DYN | kind;
  466         if ((kind & CTLTYPE) == CTLTYPE_NODE) {
  467                 /* Allocate space for children */
  468                 SYSCTL_CHILDREN_SET(oidp, malloc(sizeof(struct sysctl_oid_list),
  469                     M_SYSCTLOID, M_WAITOK));
  470                 SLIST_INIT(SYSCTL_CHILDREN(oidp));
  471         } else {
  472                 oidp->oid_arg1 = arg1;
  473                 oidp->oid_arg2 = arg2;
  474         }
  475         oidp->oid_fmt = fmt;
  476         if (descr) {
  477                 int len = strlen(descr) + 1;
  478                 oidp->oid_descr = malloc(len, M_SYSCTLOID, M_WAITOK);
  479                 if (oidp->oid_descr)
  480                         strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr);
  481         }
  482         /* Update the context, if used */
  483         if (clist != NULL)
  484                 sysctl_ctx_entry_add(clist, oidp);
  485         /* Register this oid */
  486         sysctl_register_oid(oidp);
  487         SYSCTL_XUNLOCK();
  488         return (oidp);
  489 }
  490 
  491 /*
  492  * Rename an existing oid.
  493  */
  494 void
  495 sysctl_rename_oid(struct sysctl_oid *oidp, const char *name)
  496 {
  497         ssize_t len;
  498         char *newname;
  499         void *oldname;
  500 
  501         len = strlen(name);
  502         newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
  503         bcopy(name, newname, len + 1);
  504         newname[len] = '\0';
  505         SYSCTL_XLOCK();
  506         oldname = (void *)(uintptr_t)(const void *)oidp->oid_name;
  507         oidp->oid_name = newname;
  508         SYSCTL_XUNLOCK();
  509         free(oldname, M_SYSCTLOID);
  510 }
  511 
  512 /*
  513  * Reparent an existing oid.
  514  */
  515 int
  516 sysctl_move_oid(struct sysctl_oid *oid, struct sysctl_oid_list *parent)
  517 {
  518         struct sysctl_oid *oidp;
  519 
  520         SYSCTL_XLOCK();
  521         if (oid->oid_parent == parent) {
  522                 SYSCTL_XUNLOCK();
  523                 return (0);
  524         }
  525         oidp = sysctl_find_oidname(oid->oid_name, parent);
  526         if (oidp != NULL) {
  527                 SYSCTL_XUNLOCK();
  528                 return (EEXIST);
  529         }
  530         sysctl_unregister_oid(oid);
  531         oid->oid_parent = parent;
  532         oid->oid_number = OID_AUTO;
  533         sysctl_register_oid(oid);
  534         SYSCTL_XUNLOCK();
  535         return (0);
  536 }
  537 
  538 /*
  539  * Register the kernel's oids on startup.
  540  */
  541 SET_DECLARE(sysctl_set, struct sysctl_oid);
  542 
  543 static void
  544 sysctl_register_all(void *arg)
  545 {
  546         struct sysctl_oid **oidp;
  547 
  548         sx_init(&sysctlmemlock, "sysctl mem");
  549         SYSCTL_INIT();
  550         SYSCTL_XLOCK();
  551         SET_FOREACH(oidp, sysctl_set)
  552                 sysctl_register_oid(*oidp);
  553         SYSCTL_XUNLOCK();
  554 }
  555 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
  556 
  557 /*
  558  * "Staff-functions"
  559  *
  560  * These functions implement a presently undocumented interface 
  561  * used by the sysctl program to walk the tree, and get the type
  562  * so it can print the value.
  563  * This interface is under work and consideration, and should probably
  564  * be killed with a big axe by the first person who can find the time.
  565  * (be aware though, that the proper interface isn't as obvious as it
  566  * may seem, there are various conflicting requirements.
  567  *
  568  * {0,0}        printf the entire MIB-tree.
  569  * {0,1,...}    return the name of the "..." OID.
  570  * {0,2,...}    return the next OID.
  571  * {0,3}        return the OID of the name in "new"
  572  * {0,4,...}    return the kind & format info for the "..." OID.
  573  * {0,5,...}    return the description the "..." OID.
  574  */
  575 
  576 #ifdef SYSCTL_DEBUG
  577 static void
  578 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
  579 {
  580         int k;
  581         struct sysctl_oid *oidp;
  582 
  583         SYSCTL_ASSERT_LOCKED();
  584         SLIST_FOREACH(oidp, l, oid_link) {
  585 
  586                 for (k=0; k<i; k++)
  587                         printf(" ");
  588 
  589                 printf("%d %s ", oidp->oid_number, oidp->oid_name);
  590 
  591                 printf("%c%c",
  592                         oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
  593                         oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
  594 
  595                 if (oidp->oid_handler)
  596                         printf(" *Handler");
  597 
  598                 switch (oidp->oid_kind & CTLTYPE) {
  599                         case CTLTYPE_NODE:
  600                                 printf(" Node\n");
  601                                 if (!oidp->oid_handler) {
  602                                         sysctl_sysctl_debug_dump_node(
  603                                                 oidp->oid_arg1, i+2);
  604                                 }
  605                                 break;
  606                         case CTLTYPE_INT:    printf(" Int\n"); break;
  607                         case CTLTYPE_STRING: printf(" String\n"); break;
  608                         case CTLTYPE_QUAD:   printf(" Quad\n"); break;
  609                         case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
  610                         default:             printf("\n");
  611                 }
  612 
  613         }
  614 }
  615 
  616 static int
  617 sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
  618 {
  619         int error;
  620 
  621         error = priv_check(req->td, PRIV_SYSCTL_DEBUG);
  622         if (error)
  623                 return (error);
  624         sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
  625         return (ENOENT);
  626 }
  627 
  628 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
  629         0, 0, sysctl_sysctl_debug, "-", "");
  630 #endif
  631 
  632 static int
  633 sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
  634 {
  635         int *name = (int *) arg1;
  636         u_int namelen = arg2;
  637         int error = 0;
  638         struct sysctl_oid *oid;
  639         struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
  640         char buf[10];
  641 
  642         SYSCTL_ASSERT_LOCKED();
  643         while (namelen) {
  644                 if (!lsp) {
  645                         snprintf(buf,sizeof(buf),"%d",*name);
  646                         if (req->oldidx)
  647                                 error = SYSCTL_OUT(req, ".", 1);
  648                         if (!error)
  649                                 error = SYSCTL_OUT(req, buf, strlen(buf));
  650                         if (error)
  651                                 return (error);
  652                         namelen--;
  653                         name++;
  654                         continue;
  655                 }
  656                 lsp2 = 0;
  657                 SLIST_FOREACH(oid, lsp, oid_link) {
  658                         if (oid->oid_number != *name)
  659                                 continue;
  660 
  661                         if (req->oldidx)
  662                                 error = SYSCTL_OUT(req, ".", 1);
  663                         if (!error)
  664                                 error = SYSCTL_OUT(req, oid->oid_name,
  665                                         strlen(oid->oid_name));
  666                         if (error)
  667                                 return (error);
  668 
  669                         namelen--;
  670                         name++;
  671 
  672                         if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) 
  673                                 break;
  674 
  675                         if (oid->oid_handler)
  676                                 break;
  677 
  678                         lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
  679                         break;
  680                 }
  681                 lsp = lsp2;
  682         }
  683         return (SYSCTL_OUT(req, "", 1));
  684 }
  685 
  686 static SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
  687 
  688 static int
  689 sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, 
  690         int *next, int *len, int level, struct sysctl_oid **oidpp)
  691 {
  692         struct sysctl_oid *oidp;
  693 
  694         SYSCTL_ASSERT_LOCKED();
  695         *len = level;
  696         SLIST_FOREACH(oidp, lsp, oid_link) {
  697                 *next = oidp->oid_number;
  698                 *oidpp = oidp;
  699 
  700                 if (oidp->oid_kind & CTLFLAG_SKIP)
  701                         continue;
  702 
  703                 if (!namelen) {
  704                         if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 
  705                                 return (0);
  706                         if (oidp->oid_handler) 
  707                                 /* We really should call the handler here...*/
  708                                 return (0);
  709                         lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  710                         if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, 
  711                                 len, level+1, oidpp))
  712                                 return (0);
  713                         goto emptynode;
  714                 }
  715 
  716                 if (oidp->oid_number < *name)
  717                         continue;
  718 
  719                 if (oidp->oid_number > *name) {
  720                         if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  721                                 return (0);
  722                         if (oidp->oid_handler)
  723                                 return (0);
  724                         lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  725                         if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, 
  726                                 next+1, len, level+1, oidpp))
  727                                 return (0);
  728                         goto next;
  729                 }
  730                 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  731                         continue;
  732 
  733                 if (oidp->oid_handler)
  734                         continue;
  735 
  736                 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  737                 if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, 
  738                         len, level+1, oidpp))
  739                         return (0);
  740         next:
  741                 namelen = 1;
  742         emptynode:
  743                 *len = level;
  744         }
  745         return (1);
  746 }
  747 
  748 static int
  749 sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
  750 {
  751         int *name = (int *) arg1;
  752         u_int namelen = arg2;
  753         int i, j, error;
  754         struct sysctl_oid *oid;
  755         struct sysctl_oid_list *lsp = &sysctl__children;
  756         int newoid[CTL_MAXNAME];
  757 
  758         i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
  759         if (i)
  760                 return (ENOENT);
  761         error = SYSCTL_OUT(req, newoid, j * sizeof (int));
  762         return (error);
  763 }
  764 
  765 static SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
  766 
  767 static int
  768 name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp)
  769 {
  770         int i;
  771         struct sysctl_oid *oidp;
  772         struct sysctl_oid_list *lsp = &sysctl__children;
  773         char *p;
  774 
  775         SYSCTL_ASSERT_LOCKED();
  776 
  777         if (!*name)
  778                 return (ENOENT);
  779 
  780         p = name + strlen(name) - 1 ;
  781         if (*p == '.')
  782                 *p = '\0';
  783 
  784         *len = 0;
  785 
  786         for (p = name; *p && *p != '.'; p++) 
  787                 ;
  788         i = *p;
  789         if (i == '.')
  790                 *p = '\0';
  791 
  792         oidp = SLIST_FIRST(lsp);
  793 
  794         while (oidp && *len < CTL_MAXNAME) {
  795                 if (strcmp(name, oidp->oid_name)) {
  796                         oidp = SLIST_NEXT(oidp, oid_link);
  797                         continue;
  798                 }
  799                 *oid++ = oidp->oid_number;
  800                 (*len)++;
  801 
  802                 if (!i) {
  803                         if (oidpp)
  804                                 *oidpp = oidp;
  805                         return (0);
  806                 }
  807 
  808                 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  809                         break;
  810 
  811                 if (oidp->oid_handler)
  812                         break;
  813 
  814                 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  815                 oidp = SLIST_FIRST(lsp);
  816                 name = p+1;
  817                 for (p = name; *p && *p != '.'; p++) 
  818                                 ;
  819                 i = *p;
  820                 if (i == '.')
  821                         *p = '\0';
  822         }
  823         return (ENOENT);
  824 }
  825 
  826 static int
  827 sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
  828 {
  829         char *p;
  830         int error, oid[CTL_MAXNAME], len;
  831         struct sysctl_oid *op = 0;
  832 
  833         SYSCTL_ASSERT_LOCKED();
  834 
  835         if (!req->newlen) 
  836                 return (ENOENT);
  837         if (req->newlen >= MAXPATHLEN)  /* XXX arbitrary, undocumented */
  838                 return (ENAMETOOLONG);
  839 
  840         p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
  841 
  842         error = SYSCTL_IN(req, p, req->newlen);
  843         if (error) {
  844                 free(p, M_SYSCTL);
  845                 return (error);
  846         }
  847 
  848         p [req->newlen] = '\0';
  849 
  850         error = name2oid(p, oid, &len, &op);
  851 
  852         free(p, M_SYSCTL);
  853 
  854         if (error)
  855                 return (error);
  856 
  857         error = SYSCTL_OUT(req, oid, len * sizeof *oid);
  858         return (error);
  859 }
  860 
  861 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY|CTLFLAG_MPSAFE,
  862     0, 0, sysctl_sysctl_name2oid, "I", "");
  863 
  864 static int
  865 sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
  866 {
  867         struct sysctl_oid *oid;
  868         int error;
  869 
  870         error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
  871         if (error)
  872                 return (error);
  873 
  874         if (!oid->oid_fmt)
  875                 return (ENOENT);
  876         error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
  877         if (error)
  878                 return (error);
  879         error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
  880         return (error);
  881 }
  882 
  883 
  884 static SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD|CTLFLAG_MPSAFE,
  885     sysctl_sysctl_oidfmt, "");
  886 
  887 static int
  888 sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
  889 {
  890         struct sysctl_oid *oid;
  891         int error;
  892 
  893         error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
  894         if (error)
  895                 return (error);
  896 
  897         if (!oid->oid_descr)
  898                 return (ENOENT);
  899         error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
  900         return (error);
  901 }
  902 
  903 static SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
  904 
  905 /*
  906  * Default "handler" functions.
  907  */
  908 
  909 /*
  910  * Handle an int, signed or unsigned.
  911  * Two cases:
  912  *     a variable:  point arg1 at it.
  913  *     a constant:  pass it in arg2.
  914  */
  915 
  916 int
  917 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
  918 {
  919         int tmpout, error = 0;
  920 
  921         /*
  922          * Attempt to get a coherent snapshot by making a copy of the data.
  923          */
  924         if (arg1)
  925                 tmpout = *(int *)arg1;
  926         else
  927                 tmpout = arg2;
  928         error = SYSCTL_OUT(req, &tmpout, sizeof(int));
  929 
  930         if (error || !req->newptr)
  931                 return (error);
  932 
  933         if (!arg1)
  934                 error = EPERM;
  935         else
  936                 error = SYSCTL_IN(req, arg1, sizeof(int));
  937         return (error);
  938 }
  939 
  940 /*
  941  * Based on on sysctl_handle_int() convert milliseconds into ticks.
  942  * Note: this is used by TCP.
  943  */
  944 
  945 int
  946 sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS)
  947 {
  948         int error, s, tt;
  949 
  950         tt = *(int *)arg1;
  951         s = (int)((int64_t)tt * 1000 / hz);
  952 
  953         error = sysctl_handle_int(oidp, &s, 0, req);
  954         if (error || !req->newptr)
  955                 return (error);
  956 
  957         tt = (int)((int64_t)s * hz / 1000);
  958         if (tt < 1)
  959                 return (EINVAL);
  960 
  961         *(int *)arg1 = tt;
  962         return (0);
  963 }
  964 
  965 
  966 /*
  967  * Handle a long, signed or unsigned.  arg1 points to it.
  968  */
  969 
  970 int
  971 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
  972 {
  973         int error = 0;
  974         long tmplong;
  975 #ifdef SCTL_MASK32
  976         int tmpint;
  977 #endif
  978 
  979         /*
  980          * Attempt to get a coherent snapshot by making a copy of the data.
  981          */
  982         if (!arg1)
  983                 return (EINVAL);
  984         tmplong = *(long *)arg1;
  985 #ifdef SCTL_MASK32
  986         if (req->flags & SCTL_MASK32) {
  987                 tmpint = tmplong;
  988                 error = SYSCTL_OUT(req, &tmpint, sizeof(int));
  989         } else
  990 #endif
  991                 error = SYSCTL_OUT(req, &tmplong, sizeof(long));
  992 
  993         if (error || !req->newptr)
  994                 return (error);
  995 
  996 #ifdef SCTL_MASK32
  997         if (req->flags & SCTL_MASK32) {
  998                 error = SYSCTL_IN(req, &tmpint, sizeof(int));
  999                 *(long *)arg1 = (long)tmpint;
 1000         } else
 1001 #endif
 1002                 error = SYSCTL_IN(req, arg1, sizeof(long));
 1003         return (error);
 1004 }
 1005 
 1006 /*
 1007  * Handle a 64 bit int, signed or unsigned.  arg1 points to it.
 1008  */
 1009 
 1010 int
 1011 sysctl_handle_quad(SYSCTL_HANDLER_ARGS)
 1012 {
 1013         int error = 0;
 1014         uint64_t tmpout;
 1015 
 1016         /*
 1017          * Attempt to get a coherent snapshot by making a copy of the data.
 1018          */
 1019         if (!arg1)
 1020                 return (EINVAL);
 1021         tmpout = *(uint64_t *)arg1;
 1022         error = SYSCTL_OUT(req, &tmpout, sizeof(uint64_t));
 1023 
 1024         if (error || !req->newptr)
 1025                 return (error);
 1026 
 1027         error = SYSCTL_IN(req, arg1, sizeof(uint64_t));
 1028         return (error);
 1029 }
 1030 
 1031 /*
 1032  * Handle our generic '\0' terminated 'C' string.
 1033  * Two cases:
 1034  *      a variable string:  point arg1 at it, arg2 is max length.
 1035  *      a constant string:  point arg1 at it, arg2 is zero.
 1036  */
 1037 
 1038 int
 1039 sysctl_handle_string(SYSCTL_HANDLER_ARGS)
 1040 {
 1041         int error=0;
 1042         char *tmparg;
 1043         size_t outlen;
 1044 
 1045         /*
 1046          * Attempt to get a coherent snapshot by copying to a
 1047          * temporary kernel buffer.
 1048          */
 1049 retry:
 1050         outlen = strlen((char *)arg1)+1;
 1051         tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK);
 1052 
 1053         if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) {
 1054                 free(tmparg, M_SYSCTLTMP);
 1055                 goto retry;
 1056         }
 1057 
 1058         error = SYSCTL_OUT(req, tmparg, outlen);
 1059         free(tmparg, M_SYSCTLTMP);
 1060 
 1061         if (error || !req->newptr)
 1062                 return (error);
 1063 
 1064         if ((req->newlen - req->newidx) >= arg2) {
 1065                 error = EINVAL;
 1066         } else {
 1067                 arg2 = (req->newlen - req->newidx);
 1068                 error = SYSCTL_IN(req, arg1, arg2);
 1069                 ((char *)arg1)[arg2] = '\0';
 1070         }
 1071 
 1072         return (error);
 1073 }
 1074 
 1075 /*
 1076  * Handle any kind of opaque data.
 1077  * arg1 points to it, arg2 is the size.
 1078  */
 1079 
 1080 int
 1081 sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
 1082 {
 1083         int error, tries;
 1084         u_int generation;
 1085         struct sysctl_req req2;
 1086 
 1087         /*
 1088          * Attempt to get a coherent snapshot, by using the thread
 1089          * pre-emption counter updated from within mi_switch() to
 1090          * determine if we were pre-empted during a bcopy() or
 1091          * copyout(). Make 3 attempts at doing this before giving up.
 1092          * If we encounter an error, stop immediately.
 1093          */
 1094         tries = 0;
 1095         req2 = *req;
 1096 retry:
 1097         generation = curthread->td_generation;
 1098         error = SYSCTL_OUT(req, arg1, arg2);
 1099         if (error)
 1100                 return (error);
 1101         tries++;
 1102         if (generation != curthread->td_generation && tries < 3) {
 1103                 *req = req2;
 1104                 goto retry;
 1105         }
 1106 
 1107         error = SYSCTL_IN(req, arg1, arg2);
 1108 
 1109         return (error);
 1110 }
 1111 
 1112 /*
 1113  * Transfer functions to/from kernel space.
 1114  * XXX: rather untested at this point
 1115  */
 1116 static int
 1117 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
 1118 {
 1119         size_t i = 0;
 1120 
 1121         if (req->oldptr) {
 1122                 i = l;
 1123                 if (req->oldlen <= req->oldidx)
 1124                         i = 0;
 1125                 else
 1126                         if (i > req->oldlen - req->oldidx)
 1127                                 i = req->oldlen - req->oldidx;
 1128                 if (i > 0)
 1129                         bcopy(p, (char *)req->oldptr + req->oldidx, i);
 1130         }
 1131         req->oldidx += l;
 1132         if (req->oldptr && i != l)
 1133                 return (ENOMEM);
 1134         return (0);
 1135 }
 1136 
 1137 static int
 1138 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
 1139 {
 1140         if (!req->newptr)
 1141                 return (0);
 1142         if (req->newlen - req->newidx < l)
 1143                 return (EINVAL);
 1144         bcopy((char *)req->newptr + req->newidx, p, l);
 1145         req->newidx += l;
 1146         return (0);
 1147 }
 1148 
 1149 int
 1150 kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
 1151     size_t *oldlenp, void *new, size_t newlen, size_t *retval, int flags)
 1152 {
 1153         int error = 0;
 1154         struct sysctl_req req;
 1155 
 1156         bzero(&req, sizeof req);
 1157 
 1158         req.td = td;
 1159         req.flags = flags;
 1160 
 1161         if (oldlenp) {
 1162                 req.oldlen = *oldlenp;
 1163         }
 1164         req.validlen = req.oldlen;
 1165 
 1166         if (old) {
 1167                 req.oldptr= old;
 1168         }
 1169 
 1170         if (new != NULL) {
 1171                 req.newlen = newlen;
 1172                 req.newptr = new;
 1173         }
 1174 
 1175         req.oldfunc = sysctl_old_kernel;
 1176         req.newfunc = sysctl_new_kernel;
 1177         req.lock = REQ_LOCKED;
 1178 
 1179         SYSCTL_SLOCK();
 1180         error = sysctl_root(0, name, namelen, &req);
 1181         SYSCTL_SUNLOCK();
 1182 
 1183         if (req.lock == REQ_WIRED && req.validlen > 0)
 1184                 vsunlock(req.oldptr, req.validlen);
 1185 
 1186         if (error && error != ENOMEM)
 1187                 return (error);
 1188 
 1189         if (retval) {
 1190                 if (req.oldptr && req.oldidx > req.validlen)
 1191                         *retval = req.validlen;
 1192                 else
 1193                         *retval = req.oldidx;
 1194         }
 1195         return (error);
 1196 }
 1197 
 1198 int
 1199 kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
 1200     void *new, size_t newlen, size_t *retval, int flags)
 1201 {
 1202         int oid[CTL_MAXNAME];
 1203         size_t oidlen, plen;
 1204         int error;
 1205 
 1206         oid[0] = 0;             /* sysctl internal magic */
 1207         oid[1] = 3;             /* name2oid */
 1208         oidlen = sizeof(oid);
 1209 
 1210         error = kernel_sysctl(td, oid, 2, oid, &oidlen,
 1211             (void *)name, strlen(name), &plen, flags);
 1212         if (error)
 1213                 return (error);
 1214 
 1215         error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp,
 1216             new, newlen, retval, flags);
 1217         return (error);
 1218 }
 1219 
 1220 /*
 1221  * Transfer function to/from user space.
 1222  */
 1223 static int
 1224 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
 1225 {
 1226         int error = 0;
 1227         size_t i, len, origidx;
 1228 
 1229         origidx = req->oldidx;
 1230         req->oldidx += l;
 1231         if (req->oldptr == NULL)
 1232                 return (0);
 1233         /*
 1234          * If we have not wired the user supplied buffer and we are currently
 1235          * holding locks, drop a witness warning, as it's possible that
 1236          * write operations to the user page can sleep.
 1237          */
 1238         if (req->lock != REQ_WIRED)
 1239                 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
 1240                     "sysctl_old_user()");
 1241         i = l;
 1242         len = req->validlen;
 1243         if (len <= origidx)
 1244                 i = 0;
 1245         else {
 1246                 if (i > len - origidx)
 1247                         i = len - origidx;
 1248                 error = copyout(p, (char *)req->oldptr + origidx, i);
 1249         }
 1250         if (error)
 1251                 return (error);
 1252         if (i < l)
 1253                 return (ENOMEM);
 1254         return (0);
 1255 }
 1256 
 1257 static int
 1258 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
 1259 {
 1260         int error;
 1261 
 1262         if (!req->newptr)
 1263                 return (0);
 1264         if (req->newlen - req->newidx < l)
 1265                 return (EINVAL);
 1266         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
 1267             "sysctl_new_user()");
 1268         error = copyin((char *)req->newptr + req->newidx, p, l);
 1269         req->newidx += l;
 1270         return (error);
 1271 }
 1272 
 1273 /*
 1274  * Wire the user space destination buffer.  If set to a value greater than
 1275  * zero, the len parameter limits the maximum amount of wired memory.
 1276  */
 1277 int
 1278 sysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
 1279 {
 1280         int ret;
 1281         size_t wiredlen;
 1282 
 1283         wiredlen = (len > 0 && len < req->oldlen) ? len : req->oldlen;
 1284         ret = 0;
 1285         if (req->lock == REQ_LOCKED && req->oldptr &&
 1286             req->oldfunc == sysctl_old_user) {
 1287                 if (wiredlen != 0) {
 1288                         ret = vslock(req->oldptr, wiredlen);
 1289                         if (ret != 0) {
 1290                                 if (ret != ENOMEM)
 1291                                         return (ret);
 1292                                 wiredlen = 0;
 1293                         }
 1294                 }
 1295                 req->lock = REQ_WIRED;
 1296                 req->validlen = wiredlen;
 1297         }
 1298         return (0);
 1299 }
 1300 
 1301 int
 1302 sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
 1303     int *nindx, struct sysctl_req *req)
 1304 {
 1305         struct sysctl_oid *oid;
 1306         int indx;
 1307 
 1308         SYSCTL_ASSERT_LOCKED();
 1309         oid = SLIST_FIRST(&sysctl__children);
 1310         indx = 0;
 1311         while (oid && indx < CTL_MAXNAME) {
 1312                 if (oid->oid_number == name[indx]) {
 1313                         indx++;
 1314                         if (oid->oid_kind & CTLFLAG_NOLOCK)
 1315                                 req->lock = REQ_UNLOCKED;
 1316                         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
 1317                                 if (oid->oid_handler != NULL ||
 1318                                     indx == namelen) {
 1319                                         *noid = oid;
 1320                                         if (nindx != NULL)
 1321                                                 *nindx = indx;
 1322                                         return (0);
 1323                                 }
 1324                                 oid = SLIST_FIRST(
 1325                                     (struct sysctl_oid_list *)oid->oid_arg1);
 1326                         } else if (indx == namelen) {
 1327                                 *noid = oid;
 1328                                 if (nindx != NULL)
 1329                                         *nindx = indx;
 1330                                 return (0);
 1331                         } else {
 1332                                 return (ENOTDIR);
 1333                         }
 1334                 } else {
 1335                         oid = SLIST_NEXT(oid, oid_link);
 1336                 }
 1337         }
 1338         return (ENOENT);
 1339 }
 1340 
 1341 /*
 1342  * Traverse our tree, and find the right node, execute whatever it points
 1343  * to, and return the resulting error code.
 1344  */
 1345 
 1346 static int
 1347 sysctl_root(SYSCTL_HANDLER_ARGS)
 1348 {
 1349         struct sysctl_oid *oid;
 1350         int error, indx, lvl;
 1351 
 1352         SYSCTL_ASSERT_LOCKED();
 1353 
 1354         error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
 1355         if (error)
 1356                 return (error);
 1357 
 1358         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
 1359                 /*
 1360                  * You can't call a sysctl when it's a node, but has
 1361                  * no handler.  Inform the user that it's a node.
 1362                  * The indx may or may not be the same as namelen.
 1363                  */
 1364                 if (oid->oid_handler == NULL)
 1365                         return (EISDIR);
 1366         }
 1367 
 1368         /* Is this sysctl writable? */
 1369         if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
 1370                 return (EPERM);
 1371 
 1372         KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
 1373 
 1374         /* Is this sysctl sensitive to securelevels? */
 1375         if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
 1376                 lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE;
 1377                 error = securelevel_gt(req->td->td_ucred, lvl);
 1378                 if (error)
 1379                         return (error);
 1380         }
 1381 
 1382         /* Is this sysctl writable by only privileged users? */
 1383         if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) {
 1384                 int priv;
 1385 
 1386                 if (oid->oid_kind & CTLFLAG_PRISON)
 1387                         priv = PRIV_SYSCTL_WRITEJAIL;
 1388 #ifdef VIMAGE
 1389                 else if ((oid->oid_kind & CTLFLAG_VNET) &&
 1390                      prison_owns_vnet(req->td->td_ucred))
 1391                         priv = PRIV_SYSCTL_WRITEJAIL;
 1392 #endif
 1393                 else
 1394                         priv = PRIV_SYSCTL_WRITE;
 1395                 error = priv_check(req->td, priv);
 1396                 if (error)
 1397                         return (error);
 1398         }
 1399 
 1400         if (!oid->oid_handler)
 1401                 return (EINVAL);
 1402 
 1403         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
 1404                 arg1 = (int *)arg1 + indx;
 1405                 arg2 -= indx;
 1406         } else {
 1407                 arg1 = oid->oid_arg1;
 1408                 arg2 = oid->oid_arg2;
 1409         }
 1410 #ifdef MAC
 1411         error = mac_system_check_sysctl(req->td->td_ucred, oid, arg1, arg2,
 1412             req);
 1413         if (error != 0)
 1414                 return (error);
 1415 #endif
 1416         if (!(oid->oid_kind & CTLFLAG_MPSAFE))
 1417                 mtx_lock(&Giant);
 1418         error = oid->oid_handler(oid, arg1, arg2, req);
 1419         if (!(oid->oid_kind & CTLFLAG_MPSAFE))
 1420                 mtx_unlock(&Giant);
 1421 
 1422         return (error);
 1423 }
 1424 
 1425 #ifndef _SYS_SYSPROTO_H_
 1426 struct sysctl_args {
 1427         int     *name;
 1428         u_int   namelen;
 1429         void    *old;
 1430         size_t  *oldlenp;
 1431         void    *new;
 1432         size_t  newlen;
 1433 };
 1434 #endif
 1435 int
 1436 __sysctl(struct thread *td, struct sysctl_args *uap)
 1437 {
 1438         int error, i, name[CTL_MAXNAME];
 1439         size_t j;
 1440 
 1441         if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
 1442                 return (EINVAL);
 1443 
 1444         error = copyin(uap->name, &name, uap->namelen * sizeof(int));
 1445         if (error)
 1446                 return (error);
 1447 
 1448         error = userland_sysctl(td, name, uap->namelen,
 1449                 uap->old, uap->oldlenp, 0,
 1450                 uap->new, uap->newlen, &j, 0);
 1451         if (error && error != ENOMEM)
 1452                 return (error);
 1453         if (uap->oldlenp) {
 1454                 i = copyout(&j, uap->oldlenp, sizeof(j));
 1455                 if (i)
 1456                         return (i);
 1457         }
 1458         return (error);
 1459 }
 1460 
 1461 /*
 1462  * This is used from various compatibility syscalls too.  That's why name
 1463  * must be in kernel space.
 1464  */
 1465 int
 1466 userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
 1467     size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval,
 1468     int flags)
 1469 {
 1470         int error = 0, memlocked;
 1471         struct sysctl_req req;
 1472 
 1473         bzero(&req, sizeof req);
 1474 
 1475         req.td = td;
 1476         req.flags = flags;
 1477 
 1478         if (oldlenp) {
 1479                 if (inkernel) {
 1480                         req.oldlen = *oldlenp;
 1481                 } else {
 1482                         error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
 1483                         if (error)
 1484                                 return (error);
 1485                 }
 1486         }
 1487         req.validlen = req.oldlen;
 1488 
 1489         if (old) {
 1490                 if (!useracc(old, req.oldlen, VM_PROT_WRITE))
 1491                         return (EFAULT);
 1492                 req.oldptr= old;
 1493         }
 1494 
 1495         if (new != NULL) {
 1496                 if (!useracc(new, newlen, VM_PROT_READ))
 1497                         return (EFAULT);
 1498                 req.newlen = newlen;
 1499                 req.newptr = new;
 1500         }
 1501 
 1502         req.oldfunc = sysctl_old_user;
 1503         req.newfunc = sysctl_new_user;
 1504         req.lock = REQ_LOCKED;
 1505 
 1506 #ifdef KTRACE
 1507         if (KTRPOINT(curthread, KTR_SYSCTL))
 1508                 ktrsysctl(name, namelen);
 1509 #endif
 1510 
 1511         if (req.oldlen > PAGE_SIZE) {
 1512                 memlocked = 1;
 1513                 sx_xlock(&sysctlmemlock);
 1514         } else
 1515                 memlocked = 0;
 1516         CURVNET_SET(TD_TO_VNET(td));
 1517 
 1518         for (;;) {
 1519                 req.oldidx = 0;
 1520                 req.newidx = 0;
 1521                 SYSCTL_SLOCK();
 1522                 error = sysctl_root(0, name, namelen, &req);
 1523                 SYSCTL_SUNLOCK();
 1524                 if (error != EAGAIN)
 1525                         break;
 1526                 uio_yield();
 1527         }
 1528 
 1529         CURVNET_RESTORE();
 1530 
 1531         if (req.lock == REQ_WIRED && req.validlen > 0)
 1532                 vsunlock(req.oldptr, req.validlen);
 1533         if (memlocked)
 1534                 sx_xunlock(&sysctlmemlock);
 1535 
 1536         if (error && error != ENOMEM)
 1537                 return (error);
 1538 
 1539         if (retval) {
 1540                 if (req.oldptr && req.oldidx > req.validlen)
 1541                         *retval = req.validlen;
 1542                 else
 1543                         *retval = req.oldidx;
 1544         }
 1545         return (error);
 1546 }

Cache object: a9a05cfcc1ea1c25014b620d3e308924


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.