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 /*      $NetBSD: kern_sysctl.c,v 1.218 2008/10/23 20:41:14 christos Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 2003, 2007, 2008 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Andrew Brown.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*-
   33  * Copyright (c) 1982, 1986, 1989, 1993
   34  *      The Regents of the University of California.  All rights reserved.
   35  *
   36  * This code is derived from software contributed to Berkeley by
   37  * Mike Karels at Berkeley Software Design, Inc.
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  * 3. Neither the name of the University nor the names of its contributors
   48  *    may be used to endorse or promote products derived from this software
   49  *    without specific prior written permission.
   50  *
   51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   61  * SUCH DAMAGE.
   62  *
   63  *      @(#)kern_sysctl.c       8.9 (Berkeley) 5/20/95
   64  */
   65 
   66 /*
   67  * sysctl system call.
   68  */
   69 
   70 #include <sys/cdefs.h>
   71 __KERNEL_RCSID(0, "$NetBSD: kern_sysctl.c,v 1.218 2008/10/23 20:41:14 christos Exp $");
   72 
   73 #include "opt_defcorename.h"
   74 #include "ksyms.h"
   75 
   76 #include <sys/param.h>
   77 #define __COMPAT_SYSCTL
   78 #include <sys/sysctl.h>
   79 #include <sys/systm.h>
   80 #include <sys/buf.h>
   81 #include <sys/ksyms.h>
   82 #include <sys/malloc.h>
   83 #include <sys/mount.h>
   84 #include <sys/syscallargs.h>
   85 #include <sys/kauth.h>
   86 #include <sys/ktrace.h>
   87 #include <machine/stdarg.h>
   88 
   89 #define MAXDESCLEN      1024
   90 MALLOC_DEFINE(M_SYSCTLNODE, "sysctlnode", "sysctl node structures");
   91 MALLOC_DEFINE(M_SYSCTLDATA, "sysctldata", "misc sysctl data");
   92 
   93 static int sysctl_mmap(SYSCTLFN_PROTO);
   94 static int sysctl_alloc(struct sysctlnode *, int);
   95 static int sysctl_realloc(struct sysctlnode *);
   96 
   97 static int sysctl_cvt_in(struct lwp *, int *, const void *, size_t,
   98                          struct sysctlnode *);
   99 static int sysctl_cvt_out(struct lwp *, int, const struct sysctlnode *,
  100                           void *, size_t, size_t *);
  101 
  102 static int sysctl_log_add(struct sysctllog **, const struct sysctlnode *);
  103 static int sysctl_log_realloc(struct sysctllog *);
  104 
  105 struct sysctllog {
  106         const struct sysctlnode *log_root;
  107         int *log_num;
  108         int log_size, log_left;
  109 };
  110 
  111 /*
  112  * the "root" of the new sysctl tree
  113  */
  114 struct sysctlnode sysctl_root = {
  115         .sysctl_flags = SYSCTL_VERSION|
  116             CTLFLAG_ROOT|CTLFLAG_READWRITE|
  117             CTLTYPE_NODE,
  118         .sysctl_num = 0,
  119         /*
  120          * XXX once all ports are on gcc3, we can get rid of this
  121          * ugliness and simply make it into
  122          *
  123          *      .sysctl_size = sizeof(struct sysctlnode),
  124          */
  125         sysc_init_field(_sysctl_size, sizeof(struct sysctlnode)),
  126         .sysctl_name = "(root)",
  127 };
  128 
  129 /*
  130  * link set of functions that add nodes at boot time (see also
  131  * sysctl_buildtree())
  132  */
  133 __link_set_decl(sysctl_funcs, sysctl_setup_func);
  134 
  135 /*
  136  * The `sysctl_treelock' is intended to serialize access to the sysctl
  137  * tree.  XXX This has serious problems; allocating memory and
  138  * copying data out with the lock held is insane.
  139  */
  140 krwlock_t sysctl_treelock;
  141 
  142 /*
  143  * Attributes stored in the kernel.
  144  */
  145 char hostname[MAXHOSTNAMELEN];
  146 int hostnamelen;
  147 
  148 char domainname[MAXHOSTNAMELEN];
  149 int domainnamelen;
  150 
  151 long hostid;
  152 
  153 #ifndef DEFCORENAME
  154 #define DEFCORENAME     "%n.core"
  155 #endif
  156 char defcorename[MAXPATHLEN] = DEFCORENAME;
  157 
  158 /*
  159  * ********************************************************************
  160  * Section 0: Some simple glue
  161  * ********************************************************************
  162  * By wrapping copyin(), copyout(), and copyinstr() like this, we can
  163  * stop caring about who's calling us and simplify some code a bunch.
  164  * ********************************************************************
  165  */
  166 static inline int
  167 sysctl_copyin(struct lwp *l, const void *uaddr, void *kaddr, size_t len)
  168 {
  169         int error;
  170 
  171         if (l != NULL) {
  172                 error = copyin(uaddr, kaddr, len);
  173                 ktrmibio(-1, UIO_WRITE, uaddr, len, error);
  174         } else {
  175                 error = kcopy(uaddr, kaddr, len);
  176         }
  177 
  178         return error;
  179 }
  180 
  181 static inline int
  182 sysctl_copyout(struct lwp *l, const void *kaddr, void *uaddr, size_t len)
  183 {
  184         int error;
  185 
  186         if (l != NULL) {
  187                 error = copyout(kaddr, uaddr, len);
  188                 ktrmibio(-1, UIO_READ, uaddr, len, error);
  189         } else {
  190                 error = kcopy(kaddr, uaddr, len);
  191         }
  192         
  193         return error;
  194 }
  195 
  196 static inline int
  197 sysctl_copyinstr(struct lwp *l, const void *uaddr, void *kaddr,
  198                  size_t len, size_t *done)
  199 {
  200         int error;
  201 
  202         if (l != NULL) {
  203                 error = copyinstr(uaddr, kaddr, len, done);
  204                 ktrmibio(-1, UIO_WRITE, uaddr, len, error);
  205         } else {
  206                 error = copystr(uaddr, kaddr, len, done);
  207         }
  208 
  209         return error;
  210 }
  211 
  212 /*
  213  * ********************************************************************
  214  * Initialize sysctl subsystem.
  215  * ********************************************************************
  216  */
  217 void
  218 sysctl_init(void)
  219 {
  220         sysctl_setup_func * const *sysctl_setup, f;
  221 
  222         rw_init(&sysctl_treelock);
  223 
  224         /*
  225          * dynamic mib numbers start here
  226          */
  227         sysctl_root.sysctl_num = CREATE_BASE;
  228 
  229         __link_set_foreach(sysctl_setup, sysctl_funcs) {
  230                 /*
  231                  * XXX - why do i have to coerce the pointers like this?
  232                  */
  233                 f = (void*)*sysctl_setup;
  234                 (*f)(NULL);
  235         }
  236 
  237         /*
  238          * setting this means no more permanent nodes can be added,
  239          * trees that claim to be readonly at the root now are, and if
  240          * the main tree is readonly, *everything* is.
  241          */
  242         sysctl_root.sysctl_flags |= CTLFLAG_PERMANENT;
  243 
  244 }
  245 
  246 /*
  247  * ********************************************************************
  248  * The main native sysctl system call itself.
  249  * ********************************************************************
  250  */
  251 int
  252 sys___sysctl(struct lwp *l, const struct sys___sysctl_args *uap, register_t *retval)
  253 {
  254         /* {
  255                 syscallarg(const int *) name;
  256                 syscallarg(u_int) namelen;
  257                 syscallarg(void *) old;
  258                 syscallarg(size_t *) oldlenp;
  259                 syscallarg(const void *) new;
  260                 syscallarg(size_t) newlen;
  261         } */
  262         int error, nerror, name[CTL_MAXNAME];
  263         size_t oldlen, savelen, *oldlenp;
  264 
  265         /*
  266          * get oldlen
  267          */
  268         oldlen = 0;
  269         oldlenp = SCARG(uap, oldlenp);
  270         if (oldlenp != NULL) {
  271                 error = copyin(oldlenp, &oldlen, sizeof(oldlen));
  272                 if (error)
  273                         return (error);
  274         }
  275         savelen = oldlen;
  276 
  277         /*
  278          * top-level sysctl names may or may not be non-terminal, but
  279          * we don't care
  280          */
  281         if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 1)
  282                 return (EINVAL);
  283         error = copyin(SCARG(uap, name), &name,
  284                        SCARG(uap, namelen) * sizeof(int));
  285         if (error)
  286                 return (error);
  287 
  288         ktrmib(name, SCARG(uap, namelen));
  289 
  290         sysctl_lock(SCARG(uap, new) != NULL);
  291 
  292         /*
  293          * do sysctl work (NULL means main built-in default tree)
  294          */
  295         error = sysctl_dispatch(&name[0], SCARG(uap, namelen),
  296                                 SCARG(uap, old), &oldlen,
  297                                 SCARG(uap, new), SCARG(uap, newlen),
  298                                 &name[0], l, NULL);
  299 
  300         /*
  301          * release the sysctl lock
  302          */
  303         sysctl_unlock();
  304 
  305         /*
  306          * set caller's oldlen to new value even in the face of an
  307          * error (if this gets an error and they didn't have one, they
  308          * get this one)
  309          */
  310         if (oldlenp) {
  311                 nerror = copyout(&oldlen, oldlenp, sizeof(oldlen));
  312                 if (error == 0)
  313                         error = nerror;
  314         }
  315 
  316         /*
  317          * if the only problem is that we weren't given enough space,
  318          * that's an ENOMEM error
  319          */
  320         if (error == 0 && SCARG(uap, old) != NULL && savelen < oldlen)
  321                 error = ENOMEM;
  322 
  323         return (error);
  324 }
  325 
  326 /*
  327  * ********************************************************************
  328  * Section 1: How the tree is used
  329  * ********************************************************************
  330  * Implementations of sysctl for emulations should typically need only
  331  * these three functions in this order: lock the tree, dispatch
  332  * request into it, unlock the tree.
  333  * ********************************************************************
  334  */
  335 void
  336 sysctl_lock(bool write)
  337 {
  338 
  339         if (write) {
  340                 rw_enter(&sysctl_treelock, RW_WRITER);
  341                 curlwp->l_pflag |= LP_SYSCTLWRITE;
  342         } else {
  343                 rw_enter(&sysctl_treelock, RW_READER);
  344                 curlwp->l_pflag &= ~LP_SYSCTLWRITE;
  345         }
  346 }
  347 
  348 void
  349 sysctl_relock(void)
  350 {
  351 
  352         if ((curlwp->l_pflag & LP_SYSCTLWRITE) != 0) {
  353                 rw_enter(&sysctl_treelock, RW_WRITER);
  354         } else {
  355                 rw_enter(&sysctl_treelock, RW_READER);
  356         }
  357 }
  358 
  359 /*
  360  * ********************************************************************
  361  * the main sysctl dispatch routine.  scans the given tree and picks a
  362  * function to call based on what it finds.
  363  * ********************************************************************
  364  */
  365 int
  366 sysctl_dispatch(SYSCTLFN_ARGS)
  367 {
  368         int error;
  369         sysctlfn fn;
  370         int ni;
  371 
  372         KASSERT(rw_lock_held(&sysctl_treelock));
  373 
  374         if (rnode && SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
  375                 printf("sysctl_dispatch: rnode %p wrong version\n", rnode);
  376                 error = EINVAL;
  377                 goto out;
  378         }
  379 
  380         fn = NULL;
  381         error = sysctl_locate(l, name, namelen, &rnode, &ni);
  382 
  383         if (rnode->sysctl_func != NULL) {
  384                 /*
  385                  * the node we ended up at has a function, so call it.  it can
  386                  * hand off to query or create if it wants to.
  387                  */
  388                 fn = rnode->sysctl_func;
  389         } else if (error == 0) {
  390                 /*
  391                  * we found the node they were looking for, so do a lookup.
  392                  */
  393                 fn = (sysctlfn)sysctl_lookup; /* XXX may write to rnode */
  394         } else if (error == ENOENT && (ni + 1) == namelen && name[ni] < 0) {
  395                 /*
  396                  * prospective parent node found, but the terminal node was
  397                  * not.  generic operations associate with the parent.
  398                  */
  399                 switch (name[ni]) {
  400                 case CTL_QUERY:
  401                         fn = sysctl_query;
  402                         break;
  403                 case CTL_CREATE:
  404 #if NKSYMS > 0
  405                 case CTL_CREATESYM:
  406 #endif /* NKSYMS > 0 */
  407                         if (newp == NULL) {
  408                                 error = EINVAL;
  409                                 break;
  410                         }
  411                         KASSERT(rw_write_held(&sysctl_treelock));
  412                         fn = (sysctlfn)sysctl_create; /* we own the rnode */
  413                         break;
  414                 case CTL_DESTROY:
  415                         if (newp == NULL) {
  416                                 error = EINVAL;
  417                                 break;
  418                         }
  419                         KASSERT(rw_write_held(&sysctl_treelock));
  420                         fn = (sysctlfn)sysctl_destroy; /* we own the rnode */
  421                         break;
  422                 case CTL_MMAP:
  423                         fn = (sysctlfn)sysctl_mmap; /* we own the rnode */
  424                         break;
  425                 case CTL_DESCRIBE:
  426                         fn = sysctl_describe;
  427                         break;
  428                 default:
  429                         error = EOPNOTSUPP;
  430                         break;
  431                 }
  432         }
  433 
  434         /*
  435          * after all of that, maybe we found someone who knows how to
  436          * get us what we want?
  437          */
  438         if (fn != NULL)
  439                 error = (*fn)(name + ni, namelen - ni, oldp, oldlenp,
  440                               newp, newlen, name, l, rnode);
  441         else if (error == 0)
  442                 error = EOPNOTSUPP;
  443 
  444 out:
  445         return (error);
  446 }
  447 
  448 /*
  449  * ********************************************************************
  450  * Releases the tree lock.
  451  * ********************************************************************
  452  */
  453 void
  454 sysctl_unlock(void)
  455 {
  456 
  457         rw_exit(&sysctl_treelock);
  458 }
  459 
  460 /*
  461  * ********************************************************************
  462  * Section 2: The main tree interfaces
  463  * ********************************************************************
  464  * This is how sysctl_dispatch() does its work, and you can too, by
  465  * calling these routines from helpers (though typically only
  466  * sysctl_lookup() will be used).  The tree MUST BE LOCKED when these
  467  * are called.
  468  * ********************************************************************
  469  */
  470 
  471 /*
  472  * sysctl_locate -- Finds the node matching the given mib under the
  473  * given tree (via rv).  If no tree is given, we fall back to the
  474  * native tree.  The current process (via l) is used for access
  475  * control on the tree (some nodes may be traversable only by root) and
  476  * on return, nip will show how many numbers in the mib were consumed.
  477  */
  478 int
  479 sysctl_locate(struct lwp *l, const int *name, u_int namelen,
  480               const struct sysctlnode **rnode, int *nip)
  481 {
  482         const struct sysctlnode *node, *pnode;
  483         int tn, si, ni, error, alias;
  484 
  485         KASSERT(rw_lock_held(&sysctl_treelock));
  486 
  487         /*
  488          * basic checks and setup
  489          */
  490         if (*rnode == NULL)
  491                 *rnode = &sysctl_root;
  492         if (nip)
  493                 *nip = 0;
  494         if (namelen == 0)
  495                 return (0);
  496 
  497         /*
  498          * search starts from "root"
  499          */
  500         pnode = *rnode;
  501         if (SYSCTL_VERS(pnode->sysctl_flags) != SYSCTL_VERSION) {
  502                 printf("sysctl_locate: pnode %p wrong version\n", pnode);
  503                 return (EINVAL);
  504         }
  505         node = pnode->sysctl_child;
  506         error = 0;
  507 
  508         /*
  509          * scan for node to which new node should be attached
  510          */
  511         for (ni = 0; ni < namelen; ni++) {
  512                 /*
  513                  * walked off bottom of tree
  514                  */
  515                 if (node == NULL) {
  516                         if (SYSCTL_TYPE(pnode->sysctl_flags) == CTLTYPE_NODE)
  517                                 error = ENOENT;
  518                         else
  519                                 error = ENOTDIR;
  520                         break;
  521                 }
  522                 /*
  523                  * can anyone traverse this node or only root?
  524                  */
  525                 if (l != NULL && (pnode->sysctl_flags & CTLFLAG_PRIVATE) &&
  526                     (error = kauth_authorize_system(l->l_cred,
  527                     KAUTH_SYSTEM_SYSCTL, KAUTH_REQ_SYSTEM_SYSCTL_PRVT,
  528                     NULL, NULL, NULL)) != 0)
  529                         return (error);
  530                 /*
  531                  * find a child node with the right number
  532                  */
  533                 tn = name[ni];
  534                 alias = 0;
  535 
  536                 si = 0;
  537                 /*
  538                  * Note: ANYNUMBER only matches positive integers.
  539                  * Since ANYNUMBER is only permitted on single-node
  540                  * sub-trees (eg proc), check before the loop and skip
  541                  * it if we can.
  542                  */
  543                 if ((node[si].sysctl_flags & CTLFLAG_ANYNUMBER) && (tn >= 0))
  544                         goto foundit;
  545                 for (; si < pnode->sysctl_clen; si++) {
  546                         if (node[si].sysctl_num == tn) {
  547                                 if (node[si].sysctl_flags & CTLFLAG_ALIAS) {
  548                                         if (alias++ == 4)
  549                                                 break;
  550                                         else {
  551                                                 tn = node[si].sysctl_alias;
  552                                                 si = -1;
  553                                         }
  554                                 } else
  555                                         goto foundit;
  556                         }
  557                 }
  558                 /*
  559                  * if we ran off the end, it obviously doesn't exist
  560                  */
  561                 error = ENOENT;
  562                 break;
  563 
  564                 /*
  565                  * so far so good, move on down the line
  566                  */
  567           foundit:
  568                 pnode = &node[si];
  569                 if (SYSCTL_TYPE(pnode->sysctl_flags) == CTLTYPE_NODE)
  570                         node = node[si].sysctl_child;
  571                 else
  572                         node = NULL;
  573         }
  574 
  575         *rnode = pnode;
  576         if (nip)
  577                 *nip = ni;
  578 
  579         return (error);
  580 }
  581 
  582 /*
  583  * sysctl_query -- The auto-discovery engine.  Copies out the structs
  584  * describing nodes under the given node and handles overlay trees.
  585  */
  586 int
  587 sysctl_query(SYSCTLFN_ARGS)
  588 {
  589         int error, ni, elim, v;
  590         size_t out, left, t;
  591         const struct sysctlnode *enode, *onode;
  592         struct sysctlnode qnode;
  593 
  594         KASSERT(rw_lock_held(&sysctl_treelock));
  595 
  596         if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
  597                 printf("sysctl_query: rnode %p wrong version\n", rnode);
  598                 return (EINVAL);
  599         }
  600 
  601         if (SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE)
  602                 return (ENOTDIR);
  603         if (namelen != 1 || name[0] != CTL_QUERY)
  604                 return (EINVAL);
  605 
  606         error = 0;
  607         out = 0;
  608         left = *oldlenp;
  609         elim = 0;
  610         enode = NULL;
  611 
  612         /*
  613          * translate the given request to a current node
  614          */
  615         error = sysctl_cvt_in(l, &v, newp, newlen, &qnode);
  616         if (error)
  617                 return (error);
  618 
  619         /*
  620          * if the request specifies a version, check it
  621          */
  622         if (qnode.sysctl_ver != 0) {
  623                 enode = rnode;
  624                 if (qnode.sysctl_ver != enode->sysctl_ver &&
  625                     qnode.sysctl_ver != sysctl_rootof(enode)->sysctl_ver)
  626                         return (EINVAL);
  627         }
  628 
  629         /*
  630          * process has overlay tree
  631          */
  632         if (l && l->l_proc->p_emul->e_sysctlovly) {
  633                 enode = l->l_proc->p_emul->e_sysctlovly;
  634                 elim = (name - oname);
  635                 error = sysctl_locate(l, oname, elim, &enode, NULL);
  636                 if (error == 0) {
  637                         /* ah, found parent in overlay */
  638                         elim = enode->sysctl_clen;
  639                         enode = enode->sysctl_child;
  640                 } else {
  641                         error = 0;
  642                         elim = 0;
  643                         enode = NULL;
  644                 }
  645         }
  646 
  647         for (ni = 0; ni < rnode->sysctl_clen; ni++) {
  648                 onode = &rnode->sysctl_child[ni];
  649                 if (enode && enode->sysctl_num == onode->sysctl_num) {
  650                         if (SYSCTL_TYPE(enode->sysctl_flags) != CTLTYPE_NODE)
  651                                 onode = enode;
  652                         if (--elim > 0)
  653                                 enode++;
  654                         else
  655                                 enode = NULL;
  656                 }
  657                 error = sysctl_cvt_out(l, v, onode, oldp, left, &t);
  658                 if (error)
  659                         return (error);
  660                 if (oldp != NULL)
  661                         oldp = (char*)oldp + t;
  662                 out += t;
  663                 left -= MIN(left, t);
  664         }
  665 
  666         /*
  667          * overlay trees *MUST* be entirely consumed
  668          */
  669         KASSERT(enode == NULL);
  670 
  671         *oldlenp = out;
  672 
  673         return (error);
  674 }
  675 
  676 /*
  677  * sysctl_create -- Adds a node (the description of which is taken
  678  * from newp) to the tree, returning a copy of it in the space pointed
  679  * to by oldp.  In the event that the requested slot is already taken
  680  * (either by name or by number), the offending node is returned
  681  * instead.  Yes, this is complex, but we want to make sure everything
  682  * is proper.
  683  */
  684 #ifdef SYSCTL_DEBUG_CREATE
  685 int _sysctl_create(SYSCTLFN_ARGS);
  686 int
  687 _sysctl_create(SYSCTLFN_ARGS)
  688 #else
  689 int
  690 sysctl_create(SYSCTLFN_ARGS)
  691 #endif
  692 {
  693         struct sysctlnode nnode, *node, *pnode;
  694         int error, ni, at, nm, type, sz, flags, anum, v;
  695         void *own;
  696 
  697         KASSERT(rw_write_held(&sysctl_treelock));
  698 
  699         error = 0;
  700         own = NULL;
  701         anum = -1;
  702 
  703         if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
  704                 printf("sysctl_create: rnode %p wrong version\n", rnode);
  705                 return (EINVAL);
  706         }
  707 
  708         if (namelen != 1 || (name[namelen - 1] != CTL_CREATE
  709 #if NKSYMS > 0
  710                              && name[namelen - 1] != CTL_CREATESYM
  711 #endif /* NKSYMS > 0 */
  712                              ))
  713                 return (EINVAL);
  714 
  715         /*
  716          * processes can only add nodes at securelevel 0, must be
  717          * root, and can't add nodes to a parent that's not writeable
  718          */
  719         if (l != NULL) {
  720 #ifndef SYSCTL_DISALLOW_CREATE
  721                 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL,
  722                     KAUTH_REQ_SYSTEM_SYSCTL_ADD, NULL, NULL, NULL);
  723                 if (error)
  724                         return (error);
  725                 if (!(rnode->sysctl_flags & CTLFLAG_READWRITE))
  726 #endif /* SYSCTL_DISALLOW_CREATE */
  727                         return (EPERM);
  728         }
  729 
  730         /*
  731          * nothing can add a node if:
  732          * we've finished initial set up and
  733          * the tree itself is not writeable or
  734          * the entire sysctl system is not writeable
  735          */
  736         if ((sysctl_root.sysctl_flags & CTLFLAG_PERMANENT) &&
  737             (!(sysctl_rootof(rnode)->sysctl_flags & CTLFLAG_READWRITE) ||
  738              !(sysctl_root.sysctl_flags & CTLFLAG_READWRITE)))
  739                 return (EPERM);
  740 
  741         /*
  742          * it must be a "node", not a "int" or something
  743          */
  744         if (SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE)
  745                 return (ENOTDIR);
  746         if (rnode->sysctl_flags & CTLFLAG_ALIAS) {
  747                 printf("sysctl_create: attempt to add node to aliased "
  748                        "node %p\n", rnode);
  749                 return (EINVAL);
  750         }
  751         pnode = __UNCONST(rnode); /* we are adding children to this node */
  752 
  753         if (newp == NULL)
  754                 return (EINVAL);
  755         error = sysctl_cvt_in(l, &v, newp, newlen, &nnode);
  756         if (error)
  757                 return (error);
  758 
  759         /*
  760          * nodes passed in don't *have* parents
  761          */
  762         if (nnode.sysctl_parent != NULL)
  763                 return (EINVAL);
  764 
  765         /*
  766          * if we are indeed adding it, it should be a "good" name and
  767          * number
  768          */
  769         nm = nnode.sysctl_num;
  770 #if NKSYMS > 0
  771         if (nm == CTL_CREATESYM)
  772                 nm = CTL_CREATE;
  773 #endif /* NKSYMS > 0 */
  774         if (nm < 0 && nm != CTL_CREATE)
  775                 return (EINVAL);
  776         sz = 0;
  777 
  778         /*
  779          * the name can't start with a digit
  780          */
  781         if (nnode.sysctl_name[sz] >= '' &&
  782             nnode.sysctl_name[sz] <= '9')
  783                 return (EINVAL);
  784 
  785         /*
  786          * the name must be only alphanumerics or - or _, longer than
  787          * 0 bytes and less that SYSCTL_NAMELEN
  788          */
  789         while (sz < SYSCTL_NAMELEN && nnode.sysctl_name[sz] != '\0') {
  790                 if ((nnode.sysctl_name[sz] >= '' &&
  791                      nnode.sysctl_name[sz] <= '9') ||
  792                     (nnode.sysctl_name[sz] >= 'A' &&
  793                      nnode.sysctl_name[sz] <= 'Z') ||
  794                     (nnode.sysctl_name[sz] >= 'a' &&
  795                      nnode.sysctl_name[sz] <= 'z') ||
  796                     nnode.sysctl_name[sz] == '-' ||
  797                     nnode.sysctl_name[sz] == '_')
  798                         sz++;
  799                 else
  800                         return (EINVAL);
  801         }
  802         if (sz == 0 || sz == SYSCTL_NAMELEN)
  803                 return (EINVAL);
  804 
  805         /*
  806          * various checks revolve around size vs type, etc
  807          */
  808         type = SYSCTL_TYPE(nnode.sysctl_flags);
  809         flags = SYSCTL_FLAGS(nnode.sysctl_flags);
  810         sz = nnode.sysctl_size;
  811 
  812         /*
  813          * find out if there's a collision, and if so, let the caller
  814          * know what they collided with
  815          */
  816         node = pnode->sysctl_child;
  817         at = 0;
  818         if (node) {
  819                 if ((flags | node->sysctl_flags) & CTLFLAG_ANYNUMBER)
  820                         /* No siblings for a CTLFLAG_ANYNUMBER node */
  821                         return EINVAL;
  822                 for (ni = 0; ni < pnode->sysctl_clen; ni++) {
  823                         if (nm == node[ni].sysctl_num ||
  824                             strcmp(nnode.sysctl_name, node[ni].sysctl_name) == 0) {
  825                                 /*
  826                                  * ignore error here, since we
  827                                  * are already fixed on EEXIST
  828                                  */
  829                                 (void)sysctl_cvt_out(l, v, &node[ni], oldp,
  830                                                      *oldlenp, oldlenp);
  831                                 return (EEXIST);
  832                         }
  833                         if (nm > node[ni].sysctl_num)
  834                                 at++;
  835                 }
  836         }
  837 
  838         /*
  839          * use sysctl_ver to add to the tree iff it hasn't changed
  840          */
  841         if (nnode.sysctl_ver != 0) {
  842                 /*
  843                  * a specified value must match either the parent
  844                  * node's version or the root node's version
  845                  */
  846                 if (nnode.sysctl_ver != sysctl_rootof(rnode)->sysctl_ver &&
  847                     nnode.sysctl_ver != rnode->sysctl_ver) {
  848                         return (EINVAL);
  849                 }
  850         }
  851 
  852         /*
  853          * only the kernel can assign functions to entries
  854          */
  855         if (l != NULL && nnode.sysctl_func != NULL)
  856                 return (EPERM);
  857 
  858         /*
  859          * only the kernel can create permanent entries, and only then
  860          * before the kernel is finished setting itself up
  861          */
  862         if (l != NULL && (flags & ~SYSCTL_USERFLAGS))
  863                 return (EPERM);
  864         if ((flags & CTLFLAG_PERMANENT) &
  865             (sysctl_root.sysctl_flags & CTLFLAG_PERMANENT))
  866                 return (EPERM);
  867         if ((flags & (CTLFLAG_OWNDATA | CTLFLAG_IMMEDIATE)) ==
  868             (CTLFLAG_OWNDATA | CTLFLAG_IMMEDIATE))
  869                 return (EINVAL);
  870         if ((flags & CTLFLAG_IMMEDIATE) &&
  871             type != CTLTYPE_INT && type != CTLTYPE_QUAD && type != CTLTYPE_BOOL)
  872                 return (EINVAL);
  873 
  874         /*
  875          * check size, or set it if unset and we can figure it out.
  876          * kernel created nodes are allowed to have a function instead
  877          * of a size (or a data pointer).
  878          */
  879         switch (type) {
  880         case CTLTYPE_NODE:
  881                 /*
  882                  * only *i* can assert the size of a node
  883                  */
  884                 if (flags & CTLFLAG_ALIAS) {
  885                         anum = nnode.sysctl_alias;
  886                         if (anum < 0)
  887                                 return (EINVAL);
  888                         nnode.sysctl_alias = 0;
  889                 }
  890                 if (sz != 0 || nnode.sysctl_data != NULL)
  891                         return (EINVAL);
  892                 if (nnode.sysctl_csize != 0 ||
  893                     nnode.sysctl_clen != 0 ||
  894                     nnode.sysctl_child != 0)
  895                         return (EINVAL);
  896                 if (flags & CTLFLAG_OWNDATA)
  897                         return (EINVAL);
  898                 sz = sizeof(struct sysctlnode);
  899                 break;
  900         case CTLTYPE_INT:
  901                 /*
  902                  * since an int is an int, if the size is not given or
  903                  * is wrong, we can "int-uit" it.
  904                  */
  905                 if (sz != 0 && sz != sizeof(int))
  906                         return (EINVAL);
  907                 sz = sizeof(int);
  908                 break;
  909         case CTLTYPE_STRING:
  910                 /*
  911                  * strings are a little more tricky
  912                  */
  913                 if (sz == 0) {
  914                         if (l == NULL) {
  915                                 if (nnode.sysctl_func == NULL) {
  916                                         if (nnode.sysctl_data == NULL)
  917                                                 return (EINVAL);
  918                                         else
  919                                                 sz = strlen(nnode.sysctl_data) +
  920                                                     1;
  921                                 }
  922                         } else if (nnode.sysctl_data == NULL &&
  923                                  flags & CTLFLAG_OWNDATA) {
  924                                 return (EINVAL);
  925                         } else {
  926                                 char *vp, *e;
  927                                 size_t s;
  928 
  929                                 /*
  930                                  * we want a rough idea of what the
  931                                  * size is now
  932                                  */
  933                                 vp = malloc(PAGE_SIZE, M_SYSCTLDATA,
  934                                              M_WAITOK|M_CANFAIL);
  935                                 if (vp == NULL)
  936                                         return (ENOMEM);
  937                                 e = nnode.sysctl_data;
  938                                 do {
  939                                         error = copyinstr(e, vp, PAGE_SIZE, &s);
  940                                         if (error) {
  941                                                 if (error != ENAMETOOLONG) {
  942                                                         free(vp, M_SYSCTLDATA);
  943                                                         return (error);
  944                                                 }
  945                                                 e += PAGE_SIZE;
  946                                                 if ((e - 32 * PAGE_SIZE) >
  947                                                     (char*)nnode.sysctl_data) {
  948                                                         free(vp, M_SYSCTLDATA);
  949                                                         return (ERANGE);
  950                                                 }
  951                                         }
  952                                 } while (error != 0);
  953                                 sz = s + (e - (char*)nnode.sysctl_data);
  954                                 free(vp, M_SYSCTLDATA);
  955                         }
  956                 }
  957                 break;
  958         case CTLTYPE_QUAD:
  959                 if (sz != 0 && sz != sizeof(u_quad_t))
  960                         return (EINVAL);
  961                 sz = sizeof(u_quad_t);
  962                 break;
  963         case CTLTYPE_BOOL:
  964                 /*
  965                  * since an bool is an bool, if the size is not given or
  966                  * is wrong, we can "intuit" it.
  967                  */
  968                 if (sz != 0 && sz != sizeof(bool))
  969                         return (EINVAL);
  970                 sz = sizeof(bool);
  971                 break;
  972         case CTLTYPE_STRUCT:
  973                 if (sz == 0) {
  974                         if (l != NULL || nnode.sysctl_func == NULL)
  975                                 return (EINVAL);
  976                         if (flags & CTLFLAG_OWNDATA)
  977                                 return (EINVAL);
  978                 }
  979                 break;
  980         default:
  981                 return (EINVAL);
  982         }
  983 
  984         /*
  985          * at this point, if sz is zero, we *must* have a
  986          * function to go with it and we can't own it.
  987          */
  988 
  989         /*
  990          *  l  ptr own
  991          *  0   0   0  -> EINVAL (if no func)
  992          *  0   0   1  -> own
  993          *  0   1   0  -> kptr
  994          *  0   1   1  -> kptr
  995          *  1   0   0  -> EINVAL
  996          *  1   0   1  -> own
  997          *  1   1   0  -> kptr, no own (fault on lookup)
  998          *  1   1   1  -> uptr, own
  999          */
 1000         if (type != CTLTYPE_NODE) {
 1001                 if (sz != 0) {
 1002                         if (flags & CTLFLAG_OWNDATA) {
 1003                                 own = malloc(sz, M_SYSCTLDATA,
 1004                                              M_WAITOK|M_CANFAIL);
 1005                                 if (own == NULL)
 1006                                         return ENOMEM;
 1007                                 if (nnode.sysctl_data == NULL)
 1008                                         memset(own, 0, sz);
 1009                                 else {
 1010                                         error = sysctl_copyin(l,
 1011                                             nnode.sysctl_data, own, sz);
 1012                                         if (error != 0) {
 1013                                                 free(own, M_SYSCTLDATA);
 1014                                                 return (error);
 1015                                         }
 1016                                 }
 1017                         } else if ((nnode.sysctl_data != NULL) &&
 1018                                  !(flags & CTLFLAG_IMMEDIATE)) {
 1019 #if NKSYMS > 0
 1020                                 if (name[namelen - 1] == CTL_CREATESYM) {
 1021                                         char symname[128]; /* XXX enough? */
 1022                                         u_long symaddr;
 1023                                         size_t symlen;
 1024 
 1025                                         error = sysctl_copyinstr(l,
 1026                                             nnode.sysctl_data, symname,
 1027                                             sizeof(symname), &symlen);
 1028                                         if (error)
 1029                                                 return (error);
 1030                                         error = ksyms_getval(NULL, symname,
 1031                                             &symaddr, KSYMS_EXTERN);
 1032                                         if (error)
 1033                                                 return (error); /* EINVAL? */
 1034                                         nnode.sysctl_data = (void*)symaddr;
 1035                                 }
 1036 #endif /* NKSYMS > 0 */
 1037                                 /*
 1038                                  * Ideally, we'd like to verify here
 1039                                  * that this address is acceptable,
 1040                                  * but...
 1041                                  *
 1042                                  * - it might be valid now, only to
 1043                                  *   become invalid later
 1044                                  *
 1045                                  * - it might be invalid only for the
 1046                                  *   moment and valid later
 1047                                  *
 1048                                  * - or something else.
 1049                                  *
 1050                                  * Since we can't get a good answer,
 1051                                  * we'll just accept the address as
 1052                                  * given, and fault on individual
 1053                                  * lookups.
 1054                                  */
 1055                         }
 1056                 } else if (nnode.sysctl_func == NULL)
 1057                         return (EINVAL);
 1058         }
 1059 
 1060         /*
 1061          * a process can't assign a function to a node, and the kernel
 1062          * can't create a node that has no function or data.
 1063          * (XXX somewhat redundant check)
 1064          */
 1065         if (l != NULL || nnode.sysctl_func == NULL) {
 1066                 if (type != CTLTYPE_NODE &&
 1067                     nnode.sysctl_data == NULL &&
 1068                     !(flags & CTLFLAG_IMMEDIATE) &&
 1069                     own == NULL)
 1070                         return (EINVAL);
 1071         }
 1072 
 1073 #ifdef SYSCTL_DISALLOW_KWRITE
 1074         /*
 1075          * a process can't create a writable node unless it refers to
 1076          * new data.
 1077          */
 1078         if (l != NULL && own == NULL && type != CTLTYPE_NODE &&
 1079             (flags & CTLFLAG_READWRITE) != CTLFLAG_READONLY &&
 1080             !(flags & CTLFLAG_IMMEDIATE))
 1081                 return (EPERM);
 1082 #endif /* SYSCTL_DISALLOW_KWRITE */
 1083 
 1084         /*
 1085          * make sure there's somewhere to put the new stuff.
 1086          */
 1087         if (pnode->sysctl_child == NULL) {
 1088                 if (flags & CTLFLAG_ANYNUMBER)
 1089                         error = sysctl_alloc(pnode, 1);
 1090                 else
 1091                         error = sysctl_alloc(pnode, 0);
 1092                 if (error) {
 1093                         if (own != NULL)
 1094                                 free(own, M_SYSCTLDATA);
 1095                         return (error);
 1096                 }
 1097         }
 1098         node = pnode->sysctl_child;
 1099 
 1100         /*
 1101          * no collisions, so pick a good dynamic number if we need to.
 1102          */
 1103         if (nm == CTL_CREATE) {
 1104                 nm = ++sysctl_root.sysctl_num;
 1105                 for (ni = 0; ni < pnode->sysctl_clen; ni++) {
 1106                         if (nm == node[ni].sysctl_num) {
 1107                                 nm++;
 1108                                 ni = -1;
 1109                         } else if (nm > node[ni].sysctl_num)
 1110                                 at = ni + 1;
 1111                 }
 1112         }
 1113 
 1114         /*
 1115          * oops...ran out of space
 1116          */
 1117         if (pnode->sysctl_clen == pnode->sysctl_csize) {
 1118                 error = sysctl_realloc(pnode);
 1119                 if (error) {
 1120                         if (own != NULL)
 1121                                 free(own, M_SYSCTLDATA);
 1122                         return (error);
 1123                 }
 1124                 node = pnode->sysctl_child;
 1125         }
 1126 
 1127         /*
 1128          * insert new node data
 1129          */
 1130         if (at < pnode->sysctl_clen) {
 1131                 int t;
 1132 
 1133                 /*
 1134                  * move the nodes that should come after the new one
 1135                  */
 1136                 memmove(&node[at + 1], &node[at],
 1137                         (pnode->sysctl_clen - at) * sizeof(struct sysctlnode));
 1138                 memset(&node[at], 0, sizeof(struct sysctlnode));
 1139                 node[at].sysctl_parent = pnode;
 1140                 /*
 1141                  * and...reparent any children of any moved nodes
 1142                  */
 1143                 for (ni = at; ni <= pnode->sysctl_clen; ni++)
 1144                         if (SYSCTL_TYPE(node[ni].sysctl_flags) == CTLTYPE_NODE)
 1145                                 for (t = 0; t < node[ni].sysctl_clen; t++)
 1146                                         node[ni].sysctl_child[t].sysctl_parent =
 1147                                                 &node[ni];
 1148         }
 1149         node = &node[at];
 1150         pnode->sysctl_clen++;
 1151 
 1152         strlcpy(node->sysctl_name, nnode.sysctl_name,
 1153                 sizeof(node->sysctl_name));
 1154         node->sysctl_num = nm;
 1155         node->sysctl_size = sz;
 1156         node->sysctl_flags = SYSCTL_VERSION|type|flags; /* XXX other trees */
 1157         node->sysctl_csize = 0;
 1158         node->sysctl_clen = 0;
 1159         if (own) {
 1160                 node->sysctl_data = own;
 1161                 node->sysctl_flags |= CTLFLAG_OWNDATA;
 1162         } else if (flags & CTLFLAG_ALIAS) {
 1163                 node->sysctl_alias = anum;
 1164         } else if (flags & CTLFLAG_IMMEDIATE) {
 1165                 switch (type) {
 1166                 case CTLTYPE_BOOL:
 1167                         node->sysctl_idata = nnode.sysctl_bdata;
 1168                         break;
 1169                 case CTLTYPE_INT:
 1170                         node->sysctl_idata = nnode.sysctl_idata;
 1171                         break;
 1172                 case CTLTYPE_QUAD:
 1173                         node->sysctl_qdata = nnode.sysctl_qdata;
 1174                         break;
 1175                 }
 1176         } else {
 1177                 node->sysctl_data = nnode.sysctl_data;
 1178                 node->sysctl_flags &= ~CTLFLAG_OWNDATA;
 1179         }
 1180         node->sysctl_func = nnode.sysctl_func;
 1181         node->sysctl_child = NULL;
 1182         /* node->sysctl_parent should already be done */
 1183 
 1184         /*
 1185          * update "version" on path to "root"
 1186          */
 1187         for (; rnode->sysctl_parent != NULL; rnode = rnode->sysctl_parent)
 1188                 ;
 1189         pnode = node;
 1190         for (nm = rnode->sysctl_ver + 1; pnode != NULL;
 1191              pnode = pnode->sysctl_parent)
 1192                 pnode->sysctl_ver = nm;
 1193 
 1194         /* If this fails, the node is already added - the user won't know! */
 1195         error = sysctl_cvt_out(l, v, node, oldp, *oldlenp, oldlenp);
 1196 
 1197         return (error);
 1198 }
 1199 
 1200 /*
 1201  * ********************************************************************
 1202  * A wrapper around sysctl_create() that prints the thing we're trying
 1203  * to add.
 1204  * ********************************************************************
 1205  */
 1206 #ifdef SYSCTL_DEBUG_CREATE
 1207 int
 1208 sysctl_create(SYSCTLFN_ARGS)
 1209 {
 1210         const struct sysctlnode *node;
 1211         int k, rc, ni, nl = namelen + (name - oname);
 1212 
 1213         node = newp;
 1214 
 1215         printf("namelen %d (", nl);
 1216         for (ni = 0; ni < nl - 1; ni++)
 1217                 printf(" %d", oname[ni]);
 1218         printf(" %d )\t[%s]\tflags %08x (%08x %d %zu)\n",
 1219                k = node->sysctl_num,
 1220                node->sysctl_name,
 1221                node->sysctl_flags,
 1222                SYSCTL_FLAGS(node->sysctl_flags),
 1223                SYSCTL_TYPE(node->sysctl_flags),
 1224                node->sysctl_size);
 1225 
 1226         node = rnode;
 1227         rc = _sysctl_create(SYSCTLFN_CALL(rnode));
 1228 
 1229         printf("sysctl_create(");
 1230         for (ni = 0; ni < nl - 1; ni++)
 1231                 printf(" %d", oname[ni]);
 1232         printf(" %d ) returned %d\n", k, rc);
 1233 
 1234         return (rc);
 1235 }
 1236 #endif /* SYSCTL_DEBUG_CREATE */
 1237 
 1238 /*
 1239  * sysctl_destroy -- Removes a node (as described by newp) from the
 1240  * given tree, returning (if successful) a copy of the dead node in
 1241  * oldp.  Since we're removing stuff, there's not much to check.
 1242  */
 1243 int
 1244 sysctl_destroy(SYSCTLFN_ARGS)
 1245 {
 1246         struct sysctlnode *node, *pnode, onode, nnode;
 1247         int ni, error, v;
 1248 
 1249         KASSERT(rw_write_held(&sysctl_treelock));
 1250 
 1251         if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
 1252                 printf("sysctl_destroy: rnode %p wrong version\n", rnode);
 1253                 return (EINVAL);
 1254         }
 1255 
 1256         error = 0;
 1257 
 1258         if (namelen != 1 || name[namelen - 1] != CTL_DESTROY)
 1259                 return (EINVAL);
 1260 
 1261         /*
 1262          * processes can only destroy nodes at securelevel 0, must be
 1263          * root, and can't remove nodes from a parent that's not
 1264          * writeable
 1265          */
 1266         if (l != NULL) {
 1267 #ifndef SYSCTL_DISALLOW_CREATE
 1268                 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL,
 1269                     KAUTH_REQ_SYSTEM_SYSCTL_DELETE, NULL, NULL, NULL);
 1270                 if (error)
 1271                         return (error);
 1272                 if (!(rnode->sysctl_flags & CTLFLAG_READWRITE))
 1273 #endif /* SYSCTL_DISALLOW_CREATE */
 1274                         return (EPERM);
 1275         }
 1276 
 1277         /*
 1278          * nothing can remove a node if:
 1279          * the node is permanent (checked later) or
 1280          * the tree itself is not writeable or
 1281          * the entire sysctl system is not writeable
 1282          *
 1283          * note that we ignore whether setup is complete or not,
 1284          * because these rules always apply.
 1285          */
 1286         if (!(sysctl_rootof(rnode)->sysctl_flags & CTLFLAG_READWRITE) ||
 1287             !(sysctl_root.sysctl_flags & CTLFLAG_READWRITE))
 1288                 return (EPERM);
 1289 
 1290         if (newp == NULL)
 1291                 return (EINVAL);
 1292         error = sysctl_cvt_in(l, &v, newp, newlen, &nnode);
 1293         if (error)
 1294                 return (error);
 1295         memset(&onode, 0, sizeof(struct sysctlnode));
 1296 
 1297         node = rnode->sysctl_child;
 1298         for (ni = 0; ni < rnode->sysctl_clen; ni++) {
 1299                 if (nnode.sysctl_num == node[ni].sysctl_num) {
 1300                         /*
 1301                          * if name specified, must match
 1302                          */
 1303                         if (nnode.sysctl_name[0] != '\0' &&
 1304                             strcmp(nnode.sysctl_name, node[ni].sysctl_name))
 1305                                 continue;
 1306                         /*
 1307                          * if version specified, must match
 1308                          */
 1309                         if (nnode.sysctl_ver != 0 &&
 1310                             nnode.sysctl_ver != node[ni].sysctl_ver)
 1311                                 continue;
 1312                         /*
 1313                          * this must be the one
 1314                          */
 1315                         break;
 1316                 }
 1317         }
 1318         if (ni == rnode->sysctl_clen)
 1319                 return (ENOENT);
 1320         node = &node[ni];
 1321         pnode = node->sysctl_parent;
 1322 
 1323         /*
 1324          * if the kernel says permanent, it is, so there.  nyah.
 1325          */
 1326         if (SYSCTL_FLAGS(node->sysctl_flags) & CTLFLAG_PERMANENT)
 1327                 return (EPERM);
 1328 
 1329         /*
 1330          * can't delete non-empty nodes
 1331          */
 1332         if (SYSCTL_TYPE(node->sysctl_flags) == CTLTYPE_NODE &&
 1333             node->sysctl_clen != 0)
 1334                 return (ENOTEMPTY);
 1335 
 1336         /*
 1337          * if the node "owns" data, release it now
 1338          */
 1339         if (node->sysctl_flags & CTLFLAG_OWNDATA) {
 1340                 if (node->sysctl_data != NULL)
 1341                         free(node->sysctl_data, M_SYSCTLDATA);
 1342                 node->sysctl_data = NULL;
 1343         }
 1344         if (node->sysctl_flags & CTLFLAG_OWNDESC) {
 1345                 if (node->sysctl_desc != NULL)
 1346                         /*XXXUNCONST*/
 1347                         free(__UNCONST(node->sysctl_desc), M_SYSCTLDATA);
 1348                 node->sysctl_desc = NULL;
 1349         }
 1350 
 1351         /*
 1352          * if the node to be removed is not the last one on the list,
 1353          * move the remaining nodes up, and reparent any grandchildren
 1354          */
 1355         onode = *node;
 1356         if (ni < pnode->sysctl_clen - 1) {
 1357                 int t;
 1358 
 1359                 memmove(&pnode->sysctl_child[ni], &pnode->sysctl_child[ni + 1],
 1360                         (pnode->sysctl_clen - ni - 1) *
 1361                         sizeof(struct sysctlnode));
 1362                 for (; ni < pnode->sysctl_clen - 1; ni++)
 1363                         if (SYSCTL_TYPE(pnode->sysctl_child[ni].sysctl_flags) ==
 1364                             CTLTYPE_NODE)
 1365                                 for (t = 0;
 1366                                      t < pnode->sysctl_child[ni].sysctl_clen;
 1367                                      t++)
 1368                                         pnode->sysctl_child[ni].sysctl_child[t].
 1369                                                 sysctl_parent =
 1370                                                 &pnode->sysctl_child[ni];
 1371                 ni = pnode->sysctl_clen - 1;
 1372                 node = &pnode->sysctl_child[ni];
 1373         }
 1374 
 1375         /*
 1376          * reset the space we just vacated
 1377          */
 1378         memset(node, 0, sizeof(struct sysctlnode));
 1379         node->sysctl_parent = pnode;
 1380         pnode->sysctl_clen--;
 1381 
 1382         /*
 1383          * if this parent just lost its last child, nuke the creche
 1384          */
 1385         if (pnode->sysctl_clen == 0) {
 1386                 free(pnode->sysctl_child, M_SYSCTLNODE);
 1387                 pnode->sysctl_csize = 0;
 1388                 pnode->sysctl_child = NULL;
 1389         }
 1390 
 1391         /*
 1392          * update "version" on path to "root"
 1393          */
 1394         for (; rnode->sysctl_parent != NULL; rnode = rnode->sysctl_parent)
 1395                 ;
 1396         for (ni = rnode->sysctl_ver + 1; pnode != NULL;
 1397              pnode = pnode->sysctl_parent)
 1398                 pnode->sysctl_ver = ni;
 1399 
 1400         error = sysctl_cvt_out(l, v, &onode, oldp, *oldlenp, oldlenp);
 1401 
 1402         return (error);
 1403 }
 1404 
 1405 /*
 1406  * sysctl_lookup -- Handles copyin/copyout of new and old values.
 1407  * Partial reads are globally allowed.  Only root can write to things
 1408  * unless the node says otherwise.
 1409  */
 1410 int
 1411 sysctl_lookup(SYSCTLFN_ARGS)
 1412 {
 1413         int error, rw;
 1414         size_t sz, len;
 1415         void *d;
 1416 
 1417         KASSERT(rw_lock_held(&sysctl_treelock));
 1418 
 1419         if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
 1420                 printf("sysctl_lookup: rnode %p wrong version\n", rnode);
 1421                 return (EINVAL);
 1422         }
 1423 
 1424         error = 0;
 1425 
 1426         /*
 1427          * you can't "look up" a node.  you can "query" it, but you
 1428          * can't "look it up".
 1429          */
 1430         if (SYSCTL_TYPE(rnode->sysctl_flags) == CTLTYPE_NODE || namelen != 0)
 1431                 return (EINVAL);
 1432 
 1433         /*
 1434          * some nodes are private, so only root can look into them.
 1435          */
 1436         if (l != NULL && (rnode->sysctl_flags & CTLFLAG_PRIVATE) &&
 1437             (error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL,
 1438             KAUTH_REQ_SYSTEM_SYSCTL_PRVT, NULL, NULL, NULL)) != 0)
 1439                 return (error);
 1440 
 1441         /*
 1442          * if a node wants to be writable according to different rules
 1443          * other than "only root can write to stuff unless a flag is
 1444          * set", then it needs its own function which should have been
 1445          * called and not us.
 1446          */
 1447         if (l != NULL && newp != NULL &&
 1448             !(rnode->sysctl_flags & CTLFLAG_ANYWRITE) &&
 1449             (error = kauth_authorize_generic(l->l_cred,
 1450             KAUTH_GENERIC_ISSUSER, NULL)) != 0)
 1451                 return (error);
 1452 
 1453         /*
 1454          * is this node supposedly writable?
 1455          */
 1456         rw = (rnode->sysctl_flags & CTLFLAG_READWRITE) ? 1 : 0;
 1457 
 1458         /*
 1459          * it appears not to be writable at this time, so if someone
 1460          * tried to write to it, we must tell them to go away
 1461          */
 1462         if (!rw && newp != NULL)
 1463                 return (EPERM);
 1464 
 1465         /*
 1466          * step one, copy out the stuff we have presently
 1467          */
 1468         if (rnode->sysctl_flags & CTLFLAG_IMMEDIATE) {
 1469                 /*
 1470                  * note that we discard const here because we are
 1471                  * modifying the contents of the node (which is okay
 1472                  * because it's ours)
 1473                  */
 1474                 switch (SYSCTL_TYPE(rnode->sysctl_flags)) {
 1475                 case CTLTYPE_BOOL:
 1476                         d = __UNCONST(&rnode->sysctl_bdata);
 1477                         break;
 1478                 case CTLTYPE_INT:
 1479                         d = __UNCONST(&rnode->sysctl_idata);
 1480                         break;
 1481                 case CTLTYPE_QUAD:
 1482                         d = __UNCONST(&rnode->sysctl_qdata);
 1483                         break;
 1484                 default:
 1485                         return (EINVAL);
 1486                 }
 1487         } else
 1488                 d = rnode->sysctl_data;
 1489         if (SYSCTL_TYPE(rnode->sysctl_flags) == CTLTYPE_STRING)
 1490                 sz = strlen(d) + 1; /* XXX@@@ possible fault here */
 1491         else
 1492                 sz = rnode->sysctl_size;
 1493         if (oldp != NULL)
 1494                 error = sysctl_copyout(l, d, oldp, MIN(sz, *oldlenp));
 1495         if (error)
 1496                 return (error);
 1497         *oldlenp = sz;
 1498 
 1499         /*
 1500          * are we done?
 1501          */
 1502         if (newp == NULL || newlen == 0)
 1503                 return (0);
 1504 
 1505         /*
 1506          * hmm...not done.  must now "copy in" new value.  re-adjust
 1507          * sz to maximum value (strings are "weird").
 1508          */
 1509         sz = rnode->sysctl_size;
 1510         switch (SYSCTL_TYPE(rnode->sysctl_flags)) {
 1511         case CTLTYPE_BOOL: {
 1512                 u_char tmp;
 1513                 /*
 1514                  * these data must be *exactly* the same size coming
 1515                  * in.  bool may only be true or false.
 1516                  */
 1517                 if (newlen != sz)
 1518                         return (EINVAL);
 1519                 error = sysctl_copyin(l, newp, &tmp, sz);
 1520                 if (error)
 1521                         break;
 1522                 *(bool *)d = tmp;
 1523                 break;
 1524         }
 1525         case CTLTYPE_INT:
 1526         case CTLTYPE_QUAD:
 1527         case CTLTYPE_STRUCT:
 1528                 /*
 1529                  * these data must be *exactly* the same size coming
 1530                  * in.
 1531                  */
 1532                 if (newlen != sz)
 1533                         return (EINVAL);
 1534                 error = sysctl_copyin(l, newp, d, sz);
 1535                 break;
 1536         case CTLTYPE_STRING: {
 1537                 /*
 1538                  * strings, on the other hand, can be shorter, and we
 1539                  * let userland be sloppy about the trailing nul.
 1540                  */
 1541                 char *newbuf;
 1542 
 1543                 /*
 1544                  * too much new string?
 1545                  */
 1546                 if (newlen > sz)
 1547                         return (EINVAL);
 1548 
 1549                 /*
 1550                  * temporary copy of new inbound string
 1551                  */
 1552                 len = MIN(sz, newlen);
 1553                 newbuf = malloc(len, M_SYSCTLDATA, M_WAITOK|M_CANFAIL);
 1554                 if (newbuf == NULL)
 1555                         return (ENOMEM);
 1556                 error = sysctl_copyin(l, newp, newbuf, len);
 1557                 if (error) {
 1558                         free(newbuf, M_SYSCTLDATA);
 1559                         return (error);
 1560                 }
 1561 
 1562                 /*
 1563                  * did they null terminate it, or do we have space
 1564                  * left to do it ourselves?
 1565                  */
 1566                 if (newbuf[len - 1] != '\0' && len == sz) {
 1567                         free(newbuf, M_SYSCTLDATA);
 1568                         return (EINVAL);
 1569                 }
 1570 
 1571                 /*
 1572                  * looks good, so pop it into place and zero the rest.
 1573                  */
 1574                 if (len > 0)
 1575                         memcpy(d, newbuf, len);
 1576                 if (sz != len)
 1577                         memset((char*)d + len, 0, sz - len);
 1578                 free(newbuf, M_SYSCTLDATA);
 1579                 break;
 1580         }
 1581         default:
 1582                 return (EINVAL);
 1583         }
 1584 
 1585         return (error);
 1586 }
 1587 
 1588 /*
 1589  * sysctl_mmap -- Dispatches sysctl mmap requests to those nodes that
 1590  * purport to handle it.  This interface isn't fully fleshed out yet,
 1591  * unfortunately.
 1592  */
 1593 static int
 1594 sysctl_mmap(SYSCTLFN_ARGS)
 1595 {
 1596         const struct sysctlnode *node;
 1597         struct sysctlnode nnode;
 1598         int error;
 1599 
 1600         if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
 1601                 printf("sysctl_mmap: rnode %p wrong version\n", rnode);
 1602                 return (EINVAL);
 1603         }
 1604 
 1605         /*
 1606          * let's just pretend that didn't happen, m'kay?
 1607          */
 1608         if (l == NULL)
 1609                 return (EPERM);
 1610 
 1611         /*
 1612          * is this a sysctlnode description of an mmap request?
 1613          */
 1614         if (newp == NULL || newlen != sizeof(struct sysctlnode))
 1615                 return (EINVAL);
 1616         error = sysctl_copyin(l, newp, &nnode, sizeof(nnode));
 1617         if (error)
 1618                 return (error);
 1619 
 1620         /*
 1621          * does the node they asked for exist?
 1622          */
 1623         if (namelen != 1)
 1624                 return (EOPNOTSUPP);
 1625         node = rnode;
 1626         error = sysctl_locate(l, &nnode.sysctl_num, 1, &node, NULL);
 1627         if (error)
 1628                 return (error);
 1629 
 1630         /*
 1631          * does this node that we have found purport to handle mmap?
 1632          */
 1633         if (node->sysctl_func == NULL ||
 1634             !(node->sysctl_flags & CTLFLAG_MMAP))
 1635                 return (EOPNOTSUPP);
 1636 
 1637         /*
 1638          * well...okay, they asked for it.
 1639          */
 1640         return ((*node->sysctl_func)(SYSCTLFN_CALL(node)));
 1641 }
 1642 
 1643 int
 1644 sysctl_describe(SYSCTLFN_ARGS)
 1645 {
 1646         struct sysctldesc *d;
 1647         void *bf;
 1648         size_t sz, left, tot;
 1649         int i, error, v = -1;
 1650         struct sysctlnode *node;
 1651         struct sysctlnode dnode;
 1652 
 1653         if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
 1654                 printf("sysctl_query: rnode %p wrong version\n", rnode);
 1655                 return (EINVAL);
 1656         }
 1657 
 1658         if (SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE)
 1659                 return (ENOTDIR);
 1660         if (namelen != 1 || name[0] != CTL_DESCRIBE)
 1661                 return (EINVAL);
 1662 
 1663         /*
 1664          * get ready...
 1665          */
 1666         error = 0;
 1667         d = bf = malloc(MAXDESCLEN, M_TEMP, M_WAITOK|M_CANFAIL);
 1668         if (bf == NULL)
 1669                 return ENOMEM;
 1670         tot = 0;
 1671         node = rnode->sysctl_child;
 1672         left = *oldlenp;
 1673 
 1674         /*
 1675          * no request -> all descriptions at this level
 1676          * request with desc unset -> just this node
 1677          * request with desc set -> set descr for this node
 1678          */
 1679         if (newp != NULL) {
 1680                 error = sysctl_cvt_in(l, &v, newp, newlen, &dnode);
 1681                 if (error)
 1682                         goto out;
 1683                 if (dnode.sysctl_desc != NULL) {
 1684                         /*
 1685                          * processes cannot set descriptions above
 1686                          * securelevel 0.  and must be root.  blah
 1687                          * blah blah.  a couple more checks are made
 1688                          * once we find the node we want.
 1689                          */
 1690                         if (l != NULL) {
 1691 #ifndef SYSCTL_DISALLOW_CREATE
 1692                                 error = kauth_authorize_system(l->l_cred,
 1693                                     KAUTH_SYSTEM_SYSCTL,
 1694                                     KAUTH_REQ_SYSTEM_SYSCTL_DESC, NULL,
 1695                                     NULL, NULL);
 1696                                 if (error)
 1697                                         goto out;
 1698 #else /* SYSCTL_DISALLOW_CREATE */
 1699                                 error = EPERM;
 1700                                 goto out;
 1701 #endif /* SYSCTL_DISALLOW_CREATE */
 1702                         }
 1703 
 1704                         /*
 1705                          * find node and try to set the description on it
 1706                          */
 1707                         for (i = 0; i < rnode->sysctl_clen; i++)
 1708                                 if (node[i].sysctl_num == dnode.sysctl_num)
 1709                                         break;
 1710                         if (i == rnode->sysctl_clen) {
 1711                                 error = ENOENT;
 1712                                 goto out;
 1713                         }
 1714                         node = &node[i];
 1715 
 1716                         /*
 1717                          * did the caller specify a node version?
 1718                          */
 1719                         if (dnode.sysctl_ver != 0 &&
 1720                             dnode.sysctl_ver != node->sysctl_ver) {
 1721                                 error = EINVAL;
 1722                                 goto out;
 1723                         }
 1724 
 1725                         /*
 1726                          * okay...some rules:
 1727                          * (1) if setup is done and the tree is
 1728                          *     read-only or the whole system is
 1729                          *     read-only
 1730                          * (2) no one can set a description on a
 1731                          *     permanent node (it must be set when
 1732                          *     using createv)
 1733                          * (3) processes cannot *change* a description
 1734                          * (4) processes *can*, however, set a
 1735                          *     description on a read-only node so that
 1736                          *     one can be created and then described
 1737                          *     in two steps
 1738                          * anything else come to mind?
 1739                          */
 1740                         if ((sysctl_root.sysctl_flags & CTLFLAG_PERMANENT) &&
 1741                             (!(sysctl_rootof(node)->sysctl_flags &
 1742                                CTLFLAG_READWRITE) ||
 1743                              !(sysctl_root.sysctl_flags & CTLFLAG_READWRITE))) {
 1744                                 error = EPERM;
 1745                                 goto out;
 1746                         }
 1747                         if (node->sysctl_flags & CTLFLAG_PERMANENT) {
 1748                                 error = EPERM;
 1749                                 goto out;
 1750                         }
 1751                         if (l != NULL && node->sysctl_desc != NULL) {
 1752                                 error = EPERM;
 1753                                 goto out;
 1754                         }
 1755 
 1756                         /*
 1757                          * right, let's go ahead.  the first step is
 1758                          * making the description into something the
 1759                          * node can "own", if need be.
 1760                          */
 1761                         if (l != NULL ||
 1762                             dnode.sysctl_flags & CTLFLAG_OWNDESC) {
 1763                                 char *nd, *k;
 1764 
 1765                                 k = malloc(MAXDESCLEN, M_TEMP,
 1766                                     M_WAITOK|M_CANFAIL);
 1767                                 if (k == NULL) {
 1768                                         error = ENOMEM;
 1769                                         goto out;
 1770                                 }
 1771                                 error = sysctl_copyinstr(l, dnode.sysctl_desc,
 1772                                                          k, MAXDESCLEN, &sz);
 1773                                 if (error) {
 1774                                         free(k, M_TEMP);
 1775                                         goto out;
 1776                                 }
 1777                                 nd = malloc(sz, M_SYSCTLDATA,
 1778                                             M_WAITOK|M_CANFAIL);
 1779                                 if (nd == NULL) {
 1780                                         free(k, M_TEMP);
 1781                                         error = ENOMEM;
 1782                                         goto out;
 1783                                 }
 1784                                 memcpy(nd, k, sz);
 1785                                 dnode.sysctl_flags |= CTLFLAG_OWNDESC;
 1786                                 dnode.sysctl_desc = nd;
 1787                                 free(k, M_TEMP);
 1788                         }
 1789 
 1790                         /*
 1791                          * now "release" the old description and
 1792                          * attach the new one.  ta-da.
 1793                          */
 1794                         if ((node->sysctl_flags & CTLFLAG_OWNDESC) &&
 1795                             node->sysctl_desc != NULL)
 1796                                 /*XXXUNCONST*/
 1797                                 free(__UNCONST(node->sysctl_desc), M_SYSCTLDATA);
 1798                         node->sysctl_desc = dnode.sysctl_desc;
 1799                         node->sysctl_flags |=
 1800                                 (dnode.sysctl_flags & CTLFLAG_OWNDESC);
 1801 
 1802                         /*
 1803                          * now we "fall out" and into the loop which
 1804                          * will copy the new description back out for
 1805                          * those interested parties
 1806                          */
 1807                 }
 1808         }
 1809 
 1810         /*
 1811          * scan for one description or just retrieve all descriptions
 1812          */
 1813         for (i = 0; i < rnode->sysctl_clen; i++) {
 1814                 /*
 1815                  * did they ask for the description of only one node?
 1816                  */
 1817                 if (v != -1 && node[i].sysctl_num != dnode.sysctl_num)
 1818                         continue;
 1819 
 1820                 /*
 1821                  * don't describe "private" nodes to non-suser users
 1822                  */
 1823                 if ((node[i].sysctl_flags & CTLFLAG_PRIVATE) && (l != NULL) &&
 1824                     !(kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL,
 1825                     KAUTH_REQ_SYSTEM_SYSCTL_PRVT, NULL, NULL, NULL)))
 1826                         continue;
 1827 
 1828                 /*
 1829                  * is this description "valid"?
 1830                  */
 1831                 memset(bf, 0, MAXDESCLEN);
 1832                 if (node[i].sysctl_desc == NULL)
 1833                         sz = 1;
 1834                 else if (copystr(node[i].sysctl_desc, &d->descr_str[0],
 1835                                  MAXDESCLEN - sizeof(*d), &sz) != 0) {
 1836                         /*
 1837                          * erase possible partial description
 1838                          */
 1839                         memset(bf, 0, MAXDESCLEN);
 1840                         sz = 1;
 1841                 }
 1842 
 1843                 /*
 1844                  * we've got it, stuff it into the caller's buffer
 1845                  */
 1846                 d->descr_num = node[i].sysctl_num;
 1847                 d->descr_ver = node[i].sysctl_ver;
 1848                 d->descr_len = sz; /* includes trailing nul */
 1849                 sz = (char *)NEXT_DESCR(d) - (char *)d;
 1850                 if (oldp != NULL && left >= sz) {
 1851                         error = sysctl_copyout(l, d, oldp, sz);
 1852                         if (error)
 1853                                 goto out;
 1854                         left -= sz;
 1855                         oldp = (void *)__sysc_desc_adv(oldp, d->descr_len);
 1856                 }
 1857                 tot += sz;
 1858 
 1859                 /*
 1860                  * if we get this far with v not "unset", they asked
 1861                  * for a specific node and we found it
 1862                  */
 1863                 if (v != -1)
 1864                         break;
 1865         }
 1866 
 1867         /*
 1868          * did we find it after all?
 1869          */
 1870         if (v != -1 && tot == 0)
 1871                 error = ENOENT;
 1872         else
 1873                 *oldlenp = tot;
 1874 
 1875 out:
 1876         free(bf, M_TEMP);
 1877         return (error);
 1878 }
 1879 
 1880 /*
 1881  * ********************************************************************
 1882  * Section 3: Create and destroy from inside the kernel
 1883  * ********************************************************************
 1884  * sysctl_createv() and sysctl_destroyv() are simpler-to-use
 1885  * interfaces for the kernel to fling new entries into the mib and rip
 1886  * them out later.  In the case of sysctl_createv(), the returned copy
 1887  * of the node (see sysctl_create()) will be translated back into a
 1888  * pointer to the actual node.
 1889  *
 1890  * Note that sysctl_createv() will return 0 if the create request
 1891  * matches an existing node (ala mkdir -p), and that sysctl_destroyv()
 1892  * will return 0 if the node to be destroyed already does not exist
 1893  * (aka rm -f) or if it is a parent of other nodes.
 1894  *
 1895  * This allows two (or more) different subsystems to assert sub-tree
 1896  * existence before populating their own nodes, and to remove their
 1897  * own nodes without orphaning the others when they are done.
 1898  * ********************************************************************
 1899  */
 1900 int
 1901 sysctl_createv(struct sysctllog **log, int cflags,
 1902                const struct sysctlnode **rnode, const struct sysctlnode **cnode,
 1903                int flags, int type, const char *namep, const char *descr,
 1904                sysctlfn func, u_quad_t qv, void *newp, size_t newlen,
 1905                ...)
 1906 {
 1907         va_list ap;
 1908         int error, ni, namelen, name[CTL_MAXNAME];
 1909         const struct sysctlnode *root, *pnode;
 1910         struct sysctlnode nnode, onode, *dnode;
 1911         size_t sz;
 1912 
 1913         /*
 1914          * where are we putting this?
 1915          */
 1916         if (rnode != NULL && *rnode == NULL) {
 1917                 printf("sysctl_createv: rnode NULL\n");
 1918                 return (EINVAL);
 1919         }
 1920         root = rnode ? *rnode : NULL;
 1921         if (cnode != NULL)
 1922                 *cnode = NULL;
 1923         if (cflags != 0)
 1924                 return (EINVAL);
 1925 
 1926         /*
 1927          * what is it?
 1928          */
 1929         flags = SYSCTL_VERSION|SYSCTL_TYPE(type)|SYSCTL_FLAGS(flags);
 1930         if (log != NULL)
 1931                 flags &= ~CTLFLAG_PERMANENT;
 1932 
 1933         /*
 1934          * where do we put it?
 1935          */
 1936         va_start(ap, newlen);
 1937         namelen = 0;
 1938         ni = -1;
 1939         do {
 1940                 if (++ni == CTL_MAXNAME)
 1941                         return (ENAMETOOLONG);
 1942                 name[ni] = va_arg(ap, int);
 1943                 /*
 1944                  * sorry, this is not supported from here
 1945                  */
 1946                 if (name[ni] == CTL_CREATESYM)
 1947                         return (EINVAL);
 1948         } while (name[ni] != CTL_EOL && name[ni] != CTL_CREATE);
 1949         namelen = ni + (name[ni] == CTL_CREATE ? 1 : 0);
 1950         va_end(ap);
 1951 
 1952         /*
 1953          * what's it called
 1954          */
 1955         if (strlcpy(nnode.sysctl_name, namep, sizeof(nnode.sysctl_name)) >=
 1956             sizeof(nnode.sysctl_name))
 1957                 return (ENAMETOOLONG);
 1958 
 1959         /*
 1960          * cons up the description of the new node
 1961          */
 1962         nnode.sysctl_num = name[namelen - 1];
 1963         name[namelen - 1] = CTL_CREATE;
 1964         nnode.sysctl_size = newlen;
 1965         nnode.sysctl_flags = flags;
 1966         if (type == CTLTYPE_NODE) {
 1967                 nnode.sysctl_csize = 0;
 1968                 nnode.sysctl_clen = 0;
 1969                 nnode.sysctl_child = NULL;
 1970                 if (flags & CTLFLAG_ALIAS)
 1971                         nnode.sysctl_alias = qv;
 1972         } else if (flags & CTLFLAG_IMMEDIATE) {
 1973                 switch (type) {
 1974                 case CTLTYPE_BOOL:
 1975                         nnode.sysctl_bdata = qv;
 1976                         break;
 1977                 case CTLTYPE_INT:
 1978                         nnode.sysctl_idata = qv;
 1979                         break;
 1980                 case CTLTYPE_QUAD:
 1981                         nnode.sysctl_qdata = qv;
 1982                         break;
 1983                 default:
 1984                         return (EINVAL);
 1985                 }
 1986         } else {
 1987                 nnode.sysctl_data = newp;
 1988         }
 1989         nnode.sysctl_func = func;
 1990         nnode.sysctl_parent = NULL;
 1991         nnode.sysctl_ver = 0;
 1992 
 1993         /*
 1994          * initialize lock state -- we need locks if the main tree has
 1995          * been marked as complete, but since we could be called from
 1996          * either there, or from a device driver (say, at device
 1997          * insertion), or from an lkm (at lkm load time, say), we
 1998          * don't really want to "wait"...
 1999          */
 2000         sysctl_lock(true);
 2001 
 2002         /*
 2003          * locate the prospective parent of the new node, and if we
 2004          * find it, add the new node.
 2005          */
 2006         sz = sizeof(onode);
 2007         pnode = root;
 2008         error = sysctl_locate(NULL, &name[0], namelen - 1, &pnode, &ni);
 2009         if (error) {
 2010                 printf("sysctl_createv: sysctl_locate(%s) returned %d\n",
 2011                        nnode.sysctl_name, error);
 2012                 sysctl_unlock();
 2013                 return (error);
 2014         }
 2015         error = sysctl_create(&name[ni], namelen - ni, &onode, &sz,
 2016                               &nnode, sizeof(nnode), &name[0], NULL,
 2017                               pnode);
 2018 
 2019         /*
 2020          * unfortunately the node we wanted to create is already
 2021          * there.  if the node that's already there is a reasonable
 2022          * facsimile of the node we wanted to create, just pretend
 2023          * (for the caller's benefit) that we managed to create the
 2024          * node they wanted.
 2025          */
 2026         if (error == EEXIST) {
 2027                 /* name is the same as requested... */
 2028                 if (strcmp(nnode.sysctl_name, onode.sysctl_name) == 0 &&
 2029                     /* they want the same function... */
 2030                     nnode.sysctl_func == onode.sysctl_func &&
 2031                     /* number is the same as requested, or... */
 2032                     (nnode.sysctl_num == onode.sysctl_num ||
 2033                      /* they didn't pick a number... */
 2034                      nnode.sysctl_num == CTL_CREATE)) {
 2035                         /*
 2036                          * collision here from trying to create
 2037                          * something that already existed; let's give
 2038                          * our customers a hand and tell them they got
 2039                          * what they wanted.
 2040                          */
 2041 #ifdef SYSCTL_DEBUG_CREATE
 2042                         printf("cleared\n");
 2043 #endif /* SYSCTL_DEBUG_CREATE */
 2044                         error = 0;
 2045                 }
 2046         }
 2047 
 2048         if (error == 0 &&
 2049             (cnode != NULL || log != NULL || descr != NULL)) {
 2050                 /*
 2051                  * sysctl_create() gave us back a copy of the node,
 2052                  * but we need to know where it actually is...
 2053                  */
 2054                 pnode = root;
 2055                 error = sysctl_locate(NULL, &name[0], namelen - 1, &pnode, &ni);
 2056 
 2057                 /*
 2058                  * manual scan of last layer so that aliased nodes
 2059                  * aren't followed.
 2060                  */
 2061                 if (error == 0) {
 2062                         for (ni = 0; ni < pnode->sysctl_clen; ni++)
 2063                                 if (pnode->sysctl_child[ni].sysctl_num ==
 2064                                     onode.sysctl_num)
 2065                                         break;
 2066                         if (ni < pnode->sysctl_clen)
 2067                                 pnode = &pnode->sysctl_child[ni];
 2068                         else
 2069                                 error = ENOENT;
 2070                 }
 2071 
 2072                 /*
 2073                  * not expecting an error here, but...
 2074                  */
 2075                 if (error == 0) {
 2076                         if (log != NULL)
 2077                                 sysctl_log_add(log, pnode);
 2078                         if (cnode != NULL)
 2079                                 *cnode = pnode;
 2080                         if (descr != NULL) {
 2081                                 /*
 2082                                  * allow first caller to *set* a
 2083                                  * description actually to set it
 2084                                  * 
 2085                                  * discard const here so we can attach
 2086                                  * the description
 2087                                  */
 2088                                 dnode = __UNCONST(pnode);
 2089                                 if (pnode->sysctl_desc != NULL)
 2090                                         /* skip it...we've got one */;
 2091                                 else if (flags & CTLFLAG_OWNDESC) {
 2092                                         size_t l = strlen(descr) + 1;
 2093                                         char *d = malloc(l, M_SYSCTLDATA,
 2094                                                          M_WAITOK|M_CANFAIL);
 2095                                         if (d != NULL) {
 2096                                                 memcpy(d, descr, l);
 2097                                                 dnode->sysctl_desc = d;
 2098                                                 dnode->sysctl_flags |=
 2099                                                     CTLFLAG_OWNDESC;
 2100                                         }
 2101                                 } else
 2102                                         dnode->sysctl_desc = descr;
 2103                         }
 2104                 } else {
 2105                         printf("sysctl_create succeeded but node not found?!\n");
 2106                         /*
 2107                          *  confusing, but the create said it
 2108                          * succeeded, so...
 2109                          */
 2110                         error = 0;
 2111                 }
 2112         }
 2113 
 2114         /*
 2115          * now it should be safe to release the lock state.  note that
 2116          * the pointer to the newly created node being passed back may
 2117          * not be "good" for very long.
 2118          */
 2119         sysctl_unlock();
 2120 
 2121         if (error != 0) {
 2122                 printf("sysctl_createv: sysctl_create(%s) returned %d\n",
 2123                        nnode.sysctl_name, error);
 2124 #if 0
 2125                 if (error != ENOENT)
 2126                         sysctl_dump(&onode);
 2127 #endif
 2128         }
 2129 
 2130         return (error);
 2131 }
 2132 
 2133 int
 2134 sysctl_destroyv(struct sysctlnode *rnode, ...)
 2135 {
 2136         va_list ap;
 2137         int error, name[CTL_MAXNAME], namelen, ni;
 2138         const struct sysctlnode *pnode, *node;
 2139         struct sysctlnode dnode, *onode;
 2140         size_t sz;
 2141 
 2142         va_start(ap, rnode);
 2143         namelen = 0;
 2144         ni = 0;
 2145         do {
 2146                 if (ni == CTL_MAXNAME)
 2147                         return (ENAMETOOLONG);
 2148                 name[ni] = va_arg(ap, int);
 2149         } while (name[ni++] != CTL_EOL);
 2150         namelen = ni - 1;
 2151         va_end(ap);
 2152 
 2153         /*
 2154          * i can't imagine why we'd be destroying a node when the tree
 2155          * wasn't complete, but who knows?
 2156          */
 2157         sysctl_lock(true);
 2158 
 2159         /*
 2160          * where is it?
 2161          */
 2162         node = rnode;
 2163         error = sysctl_locate(NULL, &name[0], namelen - 1, &node, &ni);
 2164         if (error) {
 2165                 /* they want it gone and it's not there, so... */
 2166                 sysctl_unlock();
 2167                 return (error == ENOENT ? 0 : error);
 2168         }
 2169 
 2170         /*
 2171          * set up the deletion
 2172          */
 2173         pnode = node;
 2174         node = &dnode;
 2175         memset(&dnode, 0, sizeof(dnode));
 2176         dnode.sysctl_flags = SYSCTL_VERSION;
 2177         dnode.sysctl_num = name[namelen - 1];
 2178 
 2179         /*
 2180          * we found it, now let's nuke it
 2181          */
 2182         name[namelen - 1] = CTL_DESTROY;
 2183         sz = 0;
 2184         error = sysctl_destroy(&name[namelen - 1], 1, NULL, &sz,
 2185                                node, sizeof(*node), &name[0], NULL,
 2186                                pnode);
 2187         if (error == ENOTEMPTY) {
 2188                 /*
 2189                  * think of trying to delete "foo" when "foo.bar"
 2190                  * (which someone else put there) is still in
 2191                  * existence
 2192                  */
 2193                 error = 0;
 2194 
 2195                 /*
 2196                  * dunno who put the description there, but if this
 2197                  * node can ever be removed, we need to make sure the
 2198                  * string doesn't go out of context.  that means we
 2199                  * need to find the node that's still there (don't use
 2200                  * sysctl_locate() because that follows aliasing).
 2201                  */
 2202                 node = pnode->sysctl_child;
 2203                 for (ni = 0; ni < pnode->sysctl_clen; ni++)
 2204                         if (node[ni].sysctl_num == dnode.sysctl_num)
 2205                                 break;
 2206                 node = (ni < pnode->sysctl_clen) ? &node[ni] : NULL;
 2207 
 2208                 /*
 2209                  * if we found it, and this node has a description,
 2210                  * and this node can be released, and it doesn't
 2211                  * already own its own description...sigh.  :)
 2212                  */
 2213                 if (node != NULL && node->sysctl_desc != NULL &&
 2214                     !(node->sysctl_flags & CTLFLAG_PERMANENT) &&
 2215                     !(node->sysctl_flags & CTLFLAG_OWNDESC)) {
 2216                         char *d;
 2217 
 2218                         sz = strlen(node->sysctl_desc) + 1;
 2219                         d = malloc(sz, M_SYSCTLDATA, M_WAITOK|M_CANFAIL);
 2220                         if (d != NULL) {
 2221                                 /*
 2222                                  * discard const so that we can
 2223                                  * re-attach the description
 2224                                  */
 2225                                 memcpy(d, node->sysctl_desc, sz);
 2226                                 onode = __UNCONST(node);
 2227                                 onode->sysctl_desc = d;
 2228                                 onode->sysctl_flags |= CTLFLAG_OWNDESC;
 2229                         } else {
 2230                                 /*
 2231                                  * XXX drop the description?  be
 2232                                  * afraid?  don't care?
 2233                                  */
 2234                         }
 2235                 }
 2236         }
 2237 
 2238         sysctl_unlock();
 2239 
 2240         return (error);
 2241 }
 2242 
 2243 /*
 2244  * ********************************************************************
 2245  * Deletes an entire n-ary tree.  Not recommended unless you know why
 2246  * you're doing it.  Personally, I don't know why you'd even think
 2247  * about it.
 2248  * ********************************************************************
 2249  */
 2250 void
 2251 sysctl_free(struct sysctlnode *rnode)
 2252 {
 2253         struct sysctlnode *node, *pnode;
 2254 
 2255         rw_enter(&sysctl_treelock, RW_WRITER);
 2256 
 2257         if (rnode == NULL)
 2258                 rnode = &sysctl_root;
 2259 
 2260         if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
 2261                 printf("sysctl_free: rnode %p wrong version\n", rnode);
 2262                 rw_exit(&sysctl_treelock);
 2263                 return;
 2264         }
 2265 
 2266         pnode = rnode;
 2267 
 2268         node = pnode->sysctl_child;
 2269         do {
 2270                 while (node != NULL && pnode->sysctl_csize > 0) {
 2271                         while (node <
 2272                                &pnode->sysctl_child[pnode->sysctl_clen] &&
 2273                                (SYSCTL_TYPE(node->sysctl_flags) !=
 2274                                 CTLTYPE_NODE ||
 2275                                 node->sysctl_csize == 0)) {
 2276                                 if (SYSCTL_FLAGS(node->sysctl_flags) &
 2277                                     CTLFLAG_OWNDATA) {
 2278                                         if (node->sysctl_data != NULL) {
 2279                                                 free(node->sysctl_data,
 2280                                                      M_SYSCTLDATA);
 2281                                                 node->sysctl_data = NULL;
 2282                                         }
 2283                                 }
 2284                                 if (SYSCTL_FLAGS(node->sysctl_flags) &
 2285                                     CTLFLAG_OWNDESC) {
 2286                                         if (node->sysctl_desc != NULL) {
 2287                                                 /*XXXUNCONST*/
 2288                                                 free(__UNCONST(node->sysctl_desc),
 2289                                                      M_SYSCTLDATA);
 2290                                                 node->sysctl_desc = NULL;
 2291                                         }
 2292                                 }
 2293                                 node++;
 2294                         }
 2295                         if (node < &pnode->sysctl_child[pnode->sysctl_clen]) {
 2296                                 pnode = node;
 2297                                 node = node->sysctl_child;
 2298                         } else
 2299                                 break;
 2300                 }
 2301                 if (pnode->sysctl_child != NULL)
 2302                         free(pnode->sysctl_child, M_SYSCTLNODE);
 2303                 pnode->sysctl_clen = 0;
 2304                 pnode->sysctl_csize = 0;
 2305                 pnode->sysctl_child = NULL;
 2306                 node = pnode;
 2307                 pnode = node->sysctl_parent;
 2308         } while (pnode != NULL && node != rnode);
 2309 
 2310         rw_exit(&sysctl_treelock);
 2311 }
 2312 
 2313 int
 2314 sysctl_log_add(struct sysctllog **logp, const struct sysctlnode *node)
 2315 {
 2316         int name[CTL_MAXNAME], namelen, i;
 2317         const struct sysctlnode *pnode;
 2318         struct sysctllog *log;
 2319 
 2320         if (node->sysctl_flags & CTLFLAG_PERMANENT)
 2321                 return (0);
 2322 
 2323         if (logp == NULL)
 2324                 return (0);
 2325 
 2326         if (*logp == NULL) {
 2327                 log = malloc(sizeof(struct sysctllog),
 2328                        M_SYSCTLDATA, M_WAITOK|M_CANFAIL);
 2329                 if (log == NULL) {
 2330                         /* XXX print error message? */
 2331                         return (-1);
 2332                 }
 2333                 log->log_num = malloc(16 * sizeof(int),
 2334                        M_SYSCTLDATA, M_WAITOK|M_CANFAIL);
 2335                 if (log->log_num == NULL) {
 2336                         /* XXX print error message? */
 2337                         free(log, M_SYSCTLDATA);
 2338                         return (-1);
 2339                 }
 2340                 memset(log->log_num, 0, 16 * sizeof(int));
 2341                 log->log_root = NULL;
 2342                 log->log_size = 16;
 2343                 log->log_left = 16;
 2344                 *logp = log;
 2345         } else
 2346                 log = *logp;
 2347 
 2348         /*
 2349          * check that the root is proper.  it's okay to record the
 2350          * address of the root of a tree.  it's the only thing that's
 2351          * guaranteed not to shift around as nodes come and go.
 2352          */
 2353         if (log->log_root == NULL)
 2354                 log->log_root = sysctl_rootof(node);
 2355         else if (log->log_root != sysctl_rootof(node)) {
 2356                 printf("sysctl: log %p root mismatch (%p)\n",
 2357                        log->log_root, sysctl_rootof(node));
 2358                 return (-1);
 2359         }
 2360 
 2361         /*
 2362          * we will copy out name in reverse order
 2363          */
 2364         for (pnode = node, namelen = 0;
 2365              pnode != NULL && !(pnode->sysctl_flags & CTLFLAG_ROOT);
 2366              pnode = pnode->sysctl_parent)
 2367                 name[namelen++] = pnode->sysctl_num;
 2368 
 2369         /*
 2370          * do we have space?
 2371          */
 2372         if (log->log_left < (namelen + 3))
 2373                 sysctl_log_realloc(log);
 2374         if (log->log_left < (namelen + 3))
 2375                 return (-1);
 2376 
 2377         /*
 2378          * stuff name in, then namelen, then node type, and finally,
 2379          * the version for non-node nodes.
 2380          */
 2381         for (i = 0; i < namelen; i++)
 2382                 log->log_num[--log->log_left] = name[i];
 2383         log->log_num[--log->log_left] = namelen;
 2384         log->log_num[--log->log_left] = SYSCTL_TYPE(node->sysctl_flags);
 2385         if (log->log_num[log->log_left] != CTLTYPE_NODE)
 2386                 log->log_num[--log->log_left] = node->sysctl_ver;
 2387         else
 2388                 log->log_num[--log->log_left] = 0;
 2389 
 2390         return (0);
 2391 }
 2392 
 2393 void
 2394 sysctl_teardown(struct sysctllog **logp)
 2395 {
 2396         const struct sysctlnode *rnode;
 2397         struct sysctlnode node;
 2398         struct sysctllog *log;
 2399         uint namelen;
 2400         int *name, t, v, error, ni;
 2401         size_t sz;
 2402 
 2403         if (logp == NULL || *logp == NULL)
 2404                 return;
 2405         log = *logp;
 2406 
 2407         rw_enter(&sysctl_treelock, RW_WRITER);
 2408         memset(&node, 0, sizeof(node));
 2409 
 2410         while (log->log_left < log->log_size) {
 2411                 KASSERT((log->log_left + 3 < log->log_size) &&
 2412                         (log->log_left + log->log_num[log->log_left + 2] <=
 2413                          log->log_size));
 2414                 v = log->log_num[log->log_left++];
 2415                 t = log->log_num[log->log_left++];
 2416                 namelen = log->log_num[log->log_left++];
 2417                 name = &log->log_num[log->log_left];
 2418 
 2419                 node.sysctl_num = name[namelen - 1];
 2420                 node.sysctl_flags = SYSCTL_VERSION|t;
 2421                 node.sysctl_ver = v;
 2422 
 2423                 rnode = log->log_root;
 2424                 error = sysctl_locate(NULL, &name[0], namelen, &rnode, &ni);
 2425                 if (error == 0) {
 2426                         name[namelen - 1] = CTL_DESTROY;
 2427                         rnode = rnode->sysctl_parent;
 2428                         sz = 0;
 2429                         (void)sysctl_destroy(&name[namelen - 1], 1, NULL,
 2430                                              &sz, &node, sizeof(node),
 2431                                              &name[0], NULL, rnode);
 2432                 }
 2433 
 2434                 log->log_left += namelen;
 2435         }
 2436 
 2437         KASSERT(log->log_size == log->log_left);
 2438         free(log->log_num, M_SYSCTLDATA);
 2439         free(log, M_SYSCTLDATA);
 2440         *logp = NULL;
 2441 
 2442         rw_exit(&sysctl_treelock);
 2443 }
 2444 
 2445 /*
 2446  * ********************************************************************
 2447  * old_sysctl -- A routine to bridge old-style internal calls to the
 2448  * new infrastructure.
 2449  * ********************************************************************
 2450  */
 2451 int
 2452 old_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
 2453            void *newp, size_t newlen, struct lwp *l)
 2454 {
 2455         int error;
 2456         size_t oldlen = 0;
 2457         size_t savelen;
 2458 
 2459         if (oldlenp) {
 2460                 oldlen = *oldlenp;
 2461         }
 2462         savelen = oldlen;
 2463 
 2464         sysctl_lock(newp != NULL);
 2465         error = sysctl_dispatch(name, namelen, oldp, &oldlen,
 2466                                 newp, newlen, name, l, NULL);
 2467         sysctl_unlock();
 2468         if (error == 0 && oldp != NULL && savelen < oldlen)
 2469                 error = ENOMEM;
 2470         if (oldlenp) {
 2471                 *oldlenp = oldlen;
 2472         }
 2473 
 2474         return (error);
 2475 }
 2476 
 2477 /*
 2478  * ********************************************************************
 2479  * Section 4: Generic helper routines
 2480  * ********************************************************************
 2481  * "helper" routines that can do more finely grained access control,
 2482  * construct structures from disparate information, create the
 2483  * appearance of more nodes and sub-trees, etc.  for example, if
 2484  * CTL_PROC wanted a helper function, it could respond to a CTL_QUERY
 2485  * with a dynamically created list of nodes that represented the
 2486  * currently running processes at that instant.
 2487  * ********************************************************************
 2488  */
 2489 
 2490 /*
 2491  * first, a few generic helpers that provide:
 2492  *
 2493  * sysctl_needfunc()            a readonly interface that emits a warning
 2494  * sysctl_notavail()            returns EOPNOTSUPP (generic error)
 2495  * sysctl_null()                an empty return buffer with no error
 2496  */
 2497 int
 2498 sysctl_needfunc(SYSCTLFN_ARGS)
 2499 {
 2500         int error;
 2501 
 2502         printf("!!SYSCTL_NEEDFUNC!!\n");
 2503 
 2504         if (newp != NULL || namelen != 0)
 2505                 return (EOPNOTSUPP);
 2506 
 2507         error = 0;
 2508         if (oldp != NULL)
 2509                 error = sysctl_copyout(l, rnode->sysctl_data, oldp,
 2510                                        MIN(rnode->sysctl_size, *oldlenp));
 2511         *oldlenp = rnode->sysctl_size;
 2512 
 2513         return (error);
 2514 }
 2515 
 2516 int
 2517 sysctl_notavail(SYSCTLFN_ARGS)
 2518 {
 2519 
 2520         if (namelen == 1 && name[0] == CTL_QUERY)
 2521                 return (sysctl_query(SYSCTLFN_CALL(rnode)));
 2522 
 2523         return (EOPNOTSUPP);
 2524 }
 2525 
 2526 int
 2527 sysctl_null(SYSCTLFN_ARGS)
 2528 {
 2529 
 2530         *oldlenp = 0;
 2531 
 2532         return (0);
 2533 }
 2534 
 2535 /*
 2536  * ********************************************************************
 2537  * Section 5: The machinery that makes it all go
 2538  * ********************************************************************
 2539  * Memory "manglement" routines.  Not much to this, eh?
 2540  * ********************************************************************
 2541  */
 2542 static int
 2543 sysctl_alloc(struct sysctlnode *p, int x)
 2544 {
 2545         int i;
 2546         struct sysctlnode *n;
 2547 
 2548         assert(p->sysctl_child == NULL);
 2549 
 2550         if (x == 1)
 2551                 n = malloc(sizeof(struct sysctlnode),
 2552                        M_SYSCTLNODE, M_WAITOK|M_CANFAIL);
 2553         else
 2554                 n = malloc(SYSCTL_DEFSIZE * sizeof(struct sysctlnode),
 2555                        M_SYSCTLNODE, M_WAITOK|M_CANFAIL);
 2556         if (n == NULL)
 2557                 return (ENOMEM);
 2558 
 2559         if (x == 1) {
 2560                 memset(n, 0, sizeof(struct sysctlnode));
 2561                 p->sysctl_csize = 1;
 2562         } else {
 2563                 memset(n, 0, SYSCTL_DEFSIZE * sizeof(struct sysctlnode));
 2564                 p->sysctl_csize = SYSCTL_DEFSIZE;
 2565         }
 2566         p->sysctl_clen = 0;
 2567 
 2568         for (i = 0; i < p->sysctl_csize; i++)
 2569                 n[i].sysctl_parent = p;
 2570 
 2571         p->sysctl_child = n;
 2572         return (0);
 2573 }
 2574 
 2575 static int
 2576 sysctl_realloc(struct sysctlnode *p)
 2577 {
 2578         int i, j;
 2579         struct sysctlnode *n;
 2580 
 2581         assert(p->sysctl_csize == p->sysctl_clen);
 2582 
 2583         /*
 2584          * how many do we have...how many should we make?
 2585          */
 2586         i = p->sysctl_clen;
 2587         n = malloc(2 * i * sizeof(struct sysctlnode), M_SYSCTLNODE,
 2588                    M_WAITOK|M_CANFAIL);
 2589         if (n == NULL)
 2590                 return (ENOMEM);
 2591 
 2592         /*
 2593          * move old children over...initialize new children
 2594          */
 2595         memcpy(n, p->sysctl_child, i * sizeof(struct sysctlnode));
 2596         memset(&n[i], 0, i * sizeof(struct sysctlnode));
 2597         p->sysctl_csize = 2 * i;
 2598 
 2599         /*
 2600          * reattach moved (and new) children to parent; if a moved
 2601          * child node has children, reattach the parent pointers of
 2602          * grandchildren
 2603          */
 2604         for (i = 0; i < p->sysctl_csize; i++) {
 2605                 n[i].sysctl_parent = p;
 2606                 if (n[i].sysctl_child != NULL) {
 2607                         for (j = 0; j < n[i].sysctl_csize; j++)
 2608                                 n[i].sysctl_child[j].sysctl_parent = &n[i];
 2609                 }
 2610         }
 2611 
 2612         /*
 2613          * get out with the old and in with the new
 2614          */
 2615         free(p->sysctl_child, M_SYSCTLNODE);
 2616         p->sysctl_child = n;
 2617 
 2618         return (0);
 2619 }
 2620 
 2621 static int
 2622 sysctl_log_realloc(struct sysctllog *log)
 2623 {
 2624         int *n, s, d;
 2625 
 2626         s = log->log_size * 2;
 2627         d = log->log_size;
 2628 
 2629         n = malloc(s * sizeof(int), M_SYSCTLDATA, M_WAITOK|M_CANFAIL);
 2630         if (n == NULL)
 2631                 return (-1);
 2632 
 2633         memset(n, 0, s * sizeof(int));
 2634         memcpy(&n[d], log->log_num, d * sizeof(int));
 2635         free(log->log_num, M_SYSCTLDATA);
 2636         log->log_num = n;
 2637         if (d)
 2638                 log->log_left += d;
 2639         else
 2640                 log->log_left = s;
 2641         log->log_size = s;
 2642 
 2643         return (0);
 2644 }
 2645 
 2646 /*
 2647  * ********************************************************************
 2648  * Section 6: Conversion between API versions wrt the sysctlnode
 2649  * ********************************************************************
 2650  */
 2651 static int
 2652 sysctl_cvt_in(struct lwp *l, int *vp, const void *i, size_t sz,
 2653               struct sysctlnode *node)
 2654 {
 2655         int error, flags;
 2656 
 2657         if (i == NULL || sz < sizeof(flags))
 2658                 return (EINVAL);
 2659 
 2660         error = sysctl_copyin(l, i, &flags, sizeof(flags));
 2661         if (error)
 2662                 return (error);
 2663 
 2664 #if (SYSCTL_VERSION != SYSCTL_VERS_1)
 2665 #error sysctl_cvt_in: no support for SYSCTL_VERSION
 2666 #endif /*  (SYSCTL_VERSION != SYSCTL_VERS_1) */
 2667 
 2668         if (sz == sizeof(*node) &&
 2669             SYSCTL_VERS(flags) == SYSCTL_VERSION) {
 2670                 error = sysctl_copyin(l, i, node, sizeof(*node));
 2671                 if (error)
 2672                         return (error);
 2673                 *vp = SYSCTL_VERSION;
 2674                 return (0);
 2675         }
 2676 
 2677         return (EINVAL);
 2678 }
 2679 
 2680 static int
 2681 sysctl_cvt_out(struct lwp *l, int v, const struct sysctlnode *i,
 2682                void *ovp, size_t left, size_t *szp)
 2683 {
 2684         size_t sz = sizeof(*i);
 2685         const void *src = i;
 2686         int error;
 2687 
 2688         switch (v) {
 2689         case SYSCTL_VERS_0:
 2690                 return (EINVAL);
 2691 
 2692 #if (SYSCTL_VERSION != SYSCTL_VERS_1)
 2693 #error sysctl_cvt_out: no support for SYSCTL_VERSION
 2694 #endif /*  (SYSCTL_VERSION != SYSCTL_VERS_1) */
 2695 
 2696         case SYSCTL_VERSION:
 2697                 /* nothing more to do here */
 2698                 break;
 2699         }
 2700 
 2701         if (ovp != NULL && left >= sz) {
 2702                 error = sysctl_copyout(l, src, ovp, sz);
 2703                 if (error)
 2704                         return (error);
 2705         }
 2706 
 2707         if (szp != NULL)
 2708                 *szp = sz;
 2709 
 2710         return (0);
 2711 }

Cache object: 2d1357e641fdaa1ba4bfc5fb6f493942


[ 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.