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/bsd/kern/kern_newsysctl.c

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

    1 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*-
   26  * Copyright (c) 1982, 1986, 1989, 1993
   27  *      The Regents of the University of California.  All rights reserved.
   28  *
   29  * This code is derived from software contributed to Berkeley by
   30  * Mike Karels at Berkeley Software Design, Inc.
   31  *
   32  * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
   33  * project, to make these variables more userfriendly.
   34  *
   35  * Redistribution and use in source and binary forms, with or without
   36  * modification, are permitted provided that the following conditions
   37  * are met:
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  * 3. All advertising materials mentioning features or use of this software
   44  *    must display the following acknowledgement:
   45  *      This product includes software developed by the University of
   46  *      California, Berkeley and its contributors.
   47  * 4. 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.4 (Berkeley) 4/14/94
   64  */
   65 
   66 
   67 #include <sys/param.h>
   68 #include <sys/buf.h>
   69 #include <sys/kernel.h>
   70 #include <sys/sysctl.h>
   71 #include <sys/malloc.h>
   72 #include <sys/proc.h>
   73 #include <sys/systm.h>
   74 
   75 /*
   76 struct sysctl_oid_list sysctl__debug_children;
   77 struct sysctl_oid_list sysctl__kern_children;
   78 struct sysctl_oid_list sysctl__net_children;
   79 struct sysctl_oid_list sysctl__sysctl_children;
   80 */
   81 
   82 extern struct sysctl_oid *newsysctl_list[];
   83 extern struct sysctl_oid *machdep_sysctl_list[];
   84 
   85 
   86 static void
   87 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i);
   88 
   89 
   90 
   91 /*
   92  * Locking and stats
   93  */
   94 static struct sysctl_lock {
   95         int     sl_lock;
   96         int     sl_want;
   97         int     sl_locked;
   98 } memlock;
   99 
  100 /*
  101  * XXX this does not belong here
  102  */
  103 static funnel_t *
  104 spl_kernel_funnel(void)
  105 {
  106         funnel_t *cfunnel;
  107 
  108         cfunnel = thread_funnel_get();
  109         if (cfunnel != kernel_flock) {
  110                 if (cfunnel != NULL)
  111                         thread_funnel_set(cfunnel, FALSE);
  112                 thread_funnel_set(kernel_flock, TRUE);
  113         }
  114         return(cfunnel);
  115 }
  116 
  117 static void
  118 splx_kernel_funnel(funnel_t *saved)
  119 {
  120         if (saved != kernel_flock) {
  121                 thread_funnel_set(kernel_flock, FALSE);
  122                 if (saved != NULL) 
  123                         thread_funnel_set(saved, TRUE);
  124         }
  125 }
  126 
  127 static int sysctl_root SYSCTL_HANDLER_ARGS;
  128 
  129 struct sysctl_oid_list sysctl__children; /* root list */
  130 
  131 /*
  132  * Initialization of the MIB tree.
  133  *
  134  * Order by number in each list.
  135  */
  136 
  137 void sysctl_register_oid(struct sysctl_oid *oidp)
  138 {
  139         struct sysctl_oid_list *parent = oidp->oid_parent;
  140         struct sysctl_oid *p;
  141         struct sysctl_oid *q;
  142         int n;
  143         funnel_t *fnl;
  144 
  145         fnl = spl_kernel_funnel();
  146 
  147         /*
  148          * If this oid has a number OID_AUTO, give it a number which
  149          * is greater than any current oid.  Make sure it is at least
  150          * 100 to leave space for pre-assigned oid numbers.
  151          */
  152 /*      sysctl_sysctl_debug_dump_node(parent, 3); */
  153         if (oidp->oid_number == OID_AUTO) {
  154                 /* First, find the highest oid in the parent list >99 */
  155                 n = 99;
  156                 SLIST_FOREACH(p, parent, oid_link) {
  157                         if (p->oid_number > n)
  158                                 n = p->oid_number;
  159                 }
  160                 oidp->oid_number = n + 1;
  161         }
  162 
  163         /*
  164          * Insert the oid into the parent's list in order.
  165          */
  166         q = NULL;
  167         SLIST_FOREACH(p, parent, oid_link) {
  168                 if (oidp->oid_number < p->oid_number)
  169                         break;
  170                 q = p;
  171         }
  172         if (q)
  173                 SLIST_INSERT_AFTER(q, oidp, oid_link);
  174         else
  175                 SLIST_INSERT_HEAD(parent, oidp, oid_link);
  176 
  177         splx_kernel_funnel(fnl);
  178 }
  179 
  180 void sysctl_unregister_oid(struct sysctl_oid *oidp)
  181 {
  182         funnel_t *fnl;
  183 
  184         fnl = spl_kernel_funnel();
  185         SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
  186         splx_kernel_funnel(fnl);
  187 }
  188 
  189 /*
  190  * Bulk-register all the oids in a linker_set.
  191  */
  192 void sysctl_register_set(struct linker_set *lsp)
  193 {
  194         int count = lsp->ls_length;
  195         int i;
  196         for (i = 0; i < count; i++)
  197                 sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);
  198 }
  199 
  200 void sysctl_unregister_set(struct linker_set *lsp)
  201 {
  202         int count = lsp->ls_length;
  203         int i;
  204         for (i = 0; i < count; i++)
  205                 sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]);
  206 }
  207 
  208 
  209 /*
  210  * Register OID's from fixed list
  211  */
  212 
  213 void sysctl_register_fixed()
  214 {
  215     int i;
  216 
  217     for (i=0; newsysctl_list[i]; i++) {
  218         sysctl_register_oid(newsysctl_list[i]);
  219     }
  220     for (i=0; machdep_sysctl_list[i]; i++) {
  221         sysctl_register_oid(machdep_sysctl_list[i]);
  222     }
  223 }
  224 
  225 /*
  226  * Register the kernel's oids on startup.
  227  */
  228 struct linker_set sysctl_set;
  229 
  230 void sysctl_register_all(void *arg)
  231 {
  232         sysctl_register_set(&sysctl_set);
  233 }
  234 
  235 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
  236 
  237 /*
  238  * "Staff-functions"
  239  *
  240  * These functions implement a presently undocumented interface 
  241  * used by the sysctl program to walk the tree, and get the type
  242  * so it can print the value.
  243  * This interface is under work and consideration, and should probably
  244  * be killed with a big axe by the first person who can find the time.
  245  * (be aware though, that the proper interface isn't as obvious as it
  246  * may seem, there are various conflicting requirements.
  247  *
  248  * {0,0}        printf the entire MIB-tree.
  249  * {0,1,...}    return the name of the "..." OID.
  250  * {0,2,...}    return the next OID.
  251  * {0,3}        return the OID of the name in "new"
  252  * {0,4,...}    return the kind & format info for the "..." OID.
  253  */
  254 
  255 static void
  256 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
  257 {
  258         int k;
  259         struct sysctl_oid *oidp;
  260 
  261         SLIST_FOREACH(oidp, l, oid_link) {
  262 
  263                 for (k=0; k<i; k++)
  264                         printf(" ");
  265 
  266                 printf("%d %s ", oidp->oid_number, oidp->oid_name);
  267 
  268                 printf("%c%c",
  269                         oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
  270                         oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
  271 
  272                 if (oidp->oid_handler)
  273                         printf(" *Handler");
  274 
  275                 switch (oidp->oid_kind & CTLTYPE) {
  276                         case CTLTYPE_NODE:
  277                                 printf(" Node\n");
  278                                 if (!oidp->oid_handler) {
  279                                         sysctl_sysctl_debug_dump_node(
  280                                                 oidp->oid_arg1, i+2);
  281                                 }
  282                                 break;
  283                         case CTLTYPE_INT:    printf(" Int\n"); break;
  284                         case CTLTYPE_STRING: printf(" String\n"); break;
  285                         case CTLTYPE_QUAD:   printf(" Quad\n"); break;
  286                         case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
  287                         default:             printf("\n");
  288                 }
  289 
  290         }
  291 }
  292 
  293 static int
  294 sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
  295 {
  296         sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
  297         return ENOENT;
  298 }
  299 
  300 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
  301         0, 0, sysctl_sysctl_debug, "-", "");
  302 
  303 static int
  304 sysctl_sysctl_name SYSCTL_HANDLER_ARGS
  305 {
  306         int *name = (int *) arg1;
  307         u_int namelen = arg2;
  308         int error = 0;
  309         struct sysctl_oid *oid;
  310         struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
  311         char buf[10];
  312 
  313         while (namelen) {
  314                 if (!lsp) {
  315                         snprintf(buf,sizeof(buf),"%d",*name);
  316                         if (req->oldidx)
  317                                 error = SYSCTL_OUT(req, ".", 1);
  318                         if (!error)
  319                                 error = SYSCTL_OUT(req, buf, strlen(buf));
  320                         if (error)
  321                                 return (error);
  322                         namelen--;
  323                         name++;
  324                         continue;
  325                 }
  326                 lsp2 = 0;
  327                 SLIST_FOREACH(oid, lsp, oid_link) {
  328                         if (oid->oid_number != *name)
  329                                 continue;
  330 
  331                         if (req->oldidx)
  332                                 error = SYSCTL_OUT(req, ".", 1);
  333                         if (!error)
  334                                 error = SYSCTL_OUT(req, oid->oid_name,
  335                                         strlen(oid->oid_name));
  336                         if (error)
  337                                 return (error);
  338 
  339                         namelen--;
  340                         name++;
  341 
  342                         if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) 
  343                                 break;
  344 
  345                         if (oid->oid_handler)
  346                                 break;
  347 
  348                         lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
  349                         break;
  350                 }
  351                 lsp = lsp2;
  352         }
  353         return (SYSCTL_OUT(req, "", 1));
  354 }
  355 
  356 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
  357 
  358 static int
  359 sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen, 
  360         int *next, int *len, int level, struct sysctl_oid **oidpp)
  361 {
  362         struct sysctl_oid *oidp;
  363 
  364         *len = level;
  365         SLIST_FOREACH(oidp, lsp, oid_link) {
  366                 *next = oidp->oid_number;
  367                 *oidpp = oidp;
  368 
  369                 if (!namelen) {
  370                         if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 
  371                                 return 0;
  372                         if (oidp->oid_handler) 
  373                                 /* We really should call the handler here...*/
  374                                 return 0;
  375                         lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  376                         if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1, 
  377                                 len, level+1, oidpp))
  378                                 return 0;
  379                         goto next;
  380                 }
  381 
  382                 if (oidp->oid_number < *name)
  383                         continue;
  384 
  385                 if (oidp->oid_number > *name) {
  386                         if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  387                                 return 0;
  388                         if (oidp->oid_handler)
  389                                 return 0;
  390                         lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  391                         if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, 
  392                                 next+1, len, level+1, oidpp))
  393                                 return (0);
  394                         goto next;
  395                 }
  396                 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  397                         continue;
  398 
  399                 if (oidp->oid_handler)
  400                         continue;
  401 
  402                 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  403                 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1, 
  404                         len, level+1, oidpp))
  405                         return (0);
  406         next:
  407                 namelen = 1;
  408                 *len = level;
  409         }
  410         return 1;
  411 }
  412 
  413 static int
  414 sysctl_sysctl_next SYSCTL_HANDLER_ARGS
  415 {
  416         int *name = (int *) arg1;
  417         u_int namelen = arg2;
  418         int i, j, error;
  419         struct sysctl_oid *oid;
  420         struct sysctl_oid_list *lsp = &sysctl__children;
  421         int newoid[CTL_MAXNAME];
  422 
  423         i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
  424         if (i)
  425                 return ENOENT;
  426         error = SYSCTL_OUT(req, newoid, j * sizeof (int));
  427         return (error);
  428 }
  429 
  430 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
  431 
  432 static int
  433 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
  434 {
  435         int i;
  436         struct sysctl_oid *oidp;
  437         struct sysctl_oid_list *lsp = &sysctl__children;
  438         char *p;
  439 
  440         if (!*name)
  441                 return ENOENT;
  442 
  443         p = name + strlen(name) - 1 ;
  444         if (*p == '.')
  445                 *p = '\0';
  446 
  447         *len = 0;
  448 
  449         for (p = name; *p && *p != '.'; p++) 
  450                 ;
  451         i = *p;
  452         if (i == '.')
  453                 *p = '\0';
  454 
  455         oidp = SLIST_FIRST(lsp);
  456 
  457         while (oidp && *len < CTL_MAXNAME) {
  458                 if (strcmp(name, oidp->oid_name)) {
  459                         oidp = SLIST_NEXT(oidp, oid_link);
  460                         continue;
  461                 }
  462                 *oid++ = oidp->oid_number;
  463                 (*len)++;
  464 
  465                 if (!i) {
  466                         if (oidpp)
  467                                 *oidpp = oidp;
  468                         return (0);
  469                 }
  470 
  471                 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  472                         break;
  473 
  474                 if (oidp->oid_handler)
  475                         break;
  476 
  477                 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  478                 oidp = SLIST_FIRST(lsp);
  479                 name = p+1;
  480                 for (p = name; *p && *p != '.'; p++) 
  481                                 ;
  482                 i = *p;
  483                 if (i == '.')
  484                         *p = '\0';
  485         }
  486         return ENOENT;
  487 }
  488 
  489 static int
  490 sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
  491 {
  492         char *p;
  493         int error, oid[CTL_MAXNAME], len;
  494         struct sysctl_oid *op = 0;
  495 
  496         if (!req->newlen) 
  497                 return ENOENT;
  498         if (req->newlen >= MAXPATHLEN)  /* XXX arbitrary, undocumented */
  499                 return (ENAMETOOLONG);
  500 
  501         p = _MALLOC(req->newlen+1, M_TEMP, M_WAITOK);
  502 
  503         if (!p)
  504             return ENOMEM;
  505 
  506         error = SYSCTL_IN(req, p, req->newlen);
  507         if (error) {
  508                 FREE(p, M_TEMP);
  509                 return (error);
  510         }
  511 
  512         p [req->newlen] = '\0';
  513 
  514         error = name2oid(p, oid, &len, &op);
  515 
  516         FREE(p, M_TEMP);
  517 
  518         if (error)
  519                 return (error);
  520 
  521         error = SYSCTL_OUT(req, oid, len * sizeof *oid);
  522         return (error);
  523 }
  524 
  525 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 
  526         sysctl_sysctl_name2oid, "I", "");
  527 
  528 static int
  529 sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
  530 {
  531         int *name = (int *) arg1, error;
  532         u_int namelen = arg2;
  533         int indx;
  534         struct sysctl_oid *oid;
  535         struct sysctl_oid_list *lsp = &sysctl__children;
  536 
  537         oid = SLIST_FIRST(lsp);
  538 
  539         indx = 0;
  540         while (oid && indx < CTL_MAXNAME) {
  541                 if (oid->oid_number == name[indx]) {
  542                         indx++;
  543                         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  544                                 if (oid->oid_handler)
  545                                         goto found;
  546                                 if (indx == namelen)
  547                                         goto found;
  548                                 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
  549                                 oid = SLIST_FIRST(lsp);
  550                         } else {
  551                                 if (indx != namelen)
  552                                         return EISDIR;
  553                                 goto found;
  554                         }
  555                 } else {
  556                         oid = SLIST_NEXT(oid, oid_link);
  557                 }
  558         }
  559         return ENOENT;
  560 found:
  561         if (!oid->oid_fmt)
  562                 return ENOENT;
  563         error = SYSCTL_OUT(req, 
  564                 &oid->oid_kind, sizeof(oid->oid_kind));
  565         if (!error)
  566                 error = SYSCTL_OUT(req, oid->oid_fmt, 
  567                         strlen(oid->oid_fmt)+1);
  568         return (error);
  569 }
  570 
  571 
  572 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
  573 
  574 /*
  575  * Default "handler" functions.
  576  */
  577 
  578 /*
  579  * Handle an int, signed or unsigned.
  580  * Two cases:
  581  *     a variable:  point arg1 at it.
  582  *     a constant:  pass it in arg2.
  583  */
  584 
  585 int
  586 sysctl_handle_int SYSCTL_HANDLER_ARGS
  587 {
  588         int error = 0;
  589 
  590         if (arg1)
  591                 error = SYSCTL_OUT(req, arg1, sizeof(int));
  592         else
  593                 error = SYSCTL_OUT(req, &arg2, sizeof(int));
  594 
  595         if (error || !req->newptr)
  596                 return (error);
  597 
  598         if (!arg1)
  599                 error = EPERM;
  600         else
  601                 error = SYSCTL_IN(req, arg1, sizeof(int));
  602         return (error);
  603 }
  604 
  605 /*
  606  * Handle a long, signed or unsigned.  arg1 points to it.
  607  */
  608 
  609 int
  610 sysctl_handle_long SYSCTL_HANDLER_ARGS
  611 {
  612         int error = 0;
  613 
  614         if (!arg1)
  615                 return (EINVAL);
  616         error = SYSCTL_OUT(req, arg1, sizeof(long));
  617 
  618         if (error || !req->newptr)
  619                 return (error);
  620 
  621         error = SYSCTL_IN(req, arg1, sizeof(long));
  622         return (error);
  623 }
  624 
  625 /*
  626  * Handle a quad, signed or unsigned.  arg1 points to it.
  627  */
  628 
  629 int
  630 sysctl_handle_quad SYSCTL_HANDLER_ARGS
  631 {
  632         int error = 0;
  633 
  634         if (!arg1)
  635                 return (EINVAL);
  636         error = SYSCTL_OUT(req, arg1, sizeof(long long));
  637 
  638         if (error || !req->newptr)
  639                 return (error);
  640 
  641         error = SYSCTL_IN(req, arg1, sizeof(long long));
  642         return (error);
  643 }
  644 
  645 /*
  646  * Expose an int value as a quad.
  647  *
  648  * This interface allows us to support interfaces defined
  649  * as using quad values while the implementation is still
  650  * using ints.
  651  */
  652 int
  653 sysctl_handle_int2quad SYSCTL_HANDLER_ARGS
  654 {
  655         int error = 0;
  656         long long val;
  657         int newval;
  658 
  659         if (!arg1)
  660                 return (EINVAL);
  661         val = (long long)*(int *)arg1;
  662         error = SYSCTL_OUT(req, &val, sizeof(long long));
  663 
  664         if (error || !req->newptr)
  665                 return (error);
  666 
  667         error = SYSCTL_IN(req, &val, sizeof(long long));
  668         if (!error) {
  669                 /*
  670                  * Value must be representable; check by
  671                  * casting and then casting back.
  672                  */
  673                 newval = (int)val;
  674                 if ((long long)newval != val) {
  675                         error = ERANGE;
  676                 } else {
  677                         *(int *)arg1 = newval;
  678                 }
  679         }
  680         return (error);
  681 }
  682 
  683 /*
  684  * Handle our generic '\0' terminated 'C' string.
  685  * Two cases:
  686  *      a variable string:  point arg1 at it, arg2 is max length.
  687  *      a constant string:  point arg1 at it, arg2 is zero.
  688  */
  689 
  690 int
  691 sysctl_handle_string SYSCTL_HANDLER_ARGS
  692 {
  693         int error=0;
  694 
  695         error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
  696 
  697         if (error || !req->newptr)
  698                 return (error);
  699 
  700         if ((req->newlen - req->newidx) >= arg2) {
  701                 error = EINVAL;
  702         } else {
  703                 arg2 = (req->newlen - req->newidx);
  704                 error = SYSCTL_IN(req, arg1, arg2);
  705                 ((char *)arg1)[arg2] = '\0';
  706         }
  707 
  708         return (error);
  709 }
  710 
  711 /*
  712  * Handle any kind of opaque data.
  713  * arg1 points to it, arg2 is the size.
  714  */
  715 
  716 int
  717 sysctl_handle_opaque SYSCTL_HANDLER_ARGS
  718 {
  719         int error;
  720 
  721         error = SYSCTL_OUT(req, arg1, arg2);
  722 
  723         if (error || !req->newptr)
  724                 return (error);
  725 
  726         error = SYSCTL_IN(req, arg1, arg2);
  727 
  728         return (error);
  729 }
  730 
  731 /*
  732  * Transfer functions to/from kernel space.
  733  */
  734 static int
  735 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
  736 {
  737         size_t i = 0;
  738         int error = 0;
  739 
  740         if (req->oldptr) {
  741                 i = l;
  742                 if (i > req->oldlen - req->oldidx)
  743                         i = req->oldlen - req->oldidx;
  744                 if (i > 0)
  745                         bcopy((void*)p, (char *)req->oldptr + req->oldidx, i);
  746         }
  747         req->oldidx += l;
  748         if (req->oldptr && i != l)
  749                 return (ENOMEM);
  750         return (0);
  751 }
  752 
  753 static int
  754 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
  755 {
  756         if (!req->newptr)
  757                 return 0;
  758         if (req->newlen - req->newidx < l)
  759                 return (EINVAL);
  760         bcopy((char *)req->newptr + req->newidx, p, l);
  761         req->newidx += l;
  762         return (0);
  763 }
  764 
  765 int
  766 kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen)
  767 {
  768         int error = 0;
  769         struct sysctl_req req;
  770         funnel_t *fnl;
  771 
  772         /*
  773          * Construct request.
  774          */
  775         bzero(&req, sizeof req);
  776         req.p = p;
  777         if (oldlenp)
  778                 req.oldlen = *oldlenp;
  779         if (old)
  780                 req.oldptr= old;
  781         if (newlen) {
  782                 req.newlen = newlen;
  783                 req.newptr = new;
  784         }
  785         req.oldfunc = sysctl_old_kernel;
  786         req.newfunc = sysctl_new_kernel;
  787         req.lock = 1;
  788 
  789         /*
  790          * Locking.  Tree traversal always begins with the kernel funnel held.
  791          */
  792         fnl = spl_kernel_funnel();
  793 
  794         /* XXX this should probably be done in a general way */
  795         while (memlock.sl_lock) {
  796                 memlock.sl_want = 1;
  797                 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
  798                 memlock.sl_locked++;
  799         }
  800         memlock.sl_lock = 1;
  801 
  802         /* make the request */
  803         error = sysctl_root(0, name, namelen, &req);
  804 
  805         /* unlock memory if required */
  806         if (req.lock == 2)
  807                 vsunlock(req.oldptr, req.oldlen, B_WRITE);
  808 
  809         memlock.sl_lock = 0;
  810 
  811         if (memlock.sl_want) {
  812                 memlock.sl_want = 0;
  813                 wakeup((caddr_t)&memlock);
  814         }
  815 
  816         /*
  817          * Undo locking.
  818          */
  819         splx_kernel_funnel(fnl);
  820 
  821         if (error && error != ENOMEM)
  822                 return (error);
  823 
  824         if (oldlenp)
  825                 *oldlenp = req.oldidx;
  826 
  827         return (error);
  828 }
  829 
  830 /*
  831  * Transfer function to/from user space.
  832  */
  833 static int
  834 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
  835 {
  836         int error = 0;
  837         size_t i = 0;
  838 
  839         if (req->oldptr) {
  840                 if (req->oldlen - req->oldidx < l)
  841                     return (ENOMEM);
  842                 i = l;
  843                 if (i > req->oldlen - req->oldidx)
  844                         i = req->oldlen - req->oldidx;
  845                 if (i > 0)
  846                         error = copyout((void*)p, (char *)req->oldptr + req->oldidx,
  847                                         i);
  848         }
  849         req->oldidx += l;
  850         if (error)
  851                 return (error);
  852         if (req->oldptr && i < l)
  853                 return (ENOMEM);
  854         return (0);
  855 }
  856 
  857 static int
  858 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
  859 {
  860         int error;
  861 
  862         if (!req->newptr)
  863                 return 0;
  864         if (req->newlen - req->newidx < l)
  865                 return (EINVAL);
  866         error = copyin((char *)req->newptr + req->newidx, p, l);
  867         req->newidx += l;
  868         return (error);
  869 }
  870 
  871 /*
  872  * Traverse our tree, and find the right node, execute whatever it points
  873  * at, and return the resulting error code.
  874  */
  875 
  876 int
  877 sysctl_root SYSCTL_HANDLER_ARGS
  878 {
  879         int *name = (int *) arg1;
  880         u_int namelen = arg2;
  881         int indx, i;
  882         struct sysctl_oid *oid;
  883         struct sysctl_oid_list *lsp = &sysctl__children;
  884         int error;
  885 
  886         oid = SLIST_FIRST(lsp);
  887 
  888         indx = 0;
  889         while (oid && indx < CTL_MAXNAME) {
  890                 if (oid->oid_number == name[indx]) {
  891                         indx++;
  892                         if (oid->oid_kind & CTLFLAG_NOLOCK)
  893                                 req->lock = 0;
  894                         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  895                                 if (oid->oid_handler)
  896                                         goto found;
  897                                 if (indx == namelen)
  898                                         return ENOENT;
  899                                 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
  900                                 oid = SLIST_FIRST(lsp);
  901                         } else {
  902                                 if (indx != namelen)
  903                                         return EISDIR;
  904                                 goto found;
  905                         }
  906                 } else {
  907                         oid = SLIST_NEXT(oid, oid_link);
  908                 }
  909         }
  910         return ENOENT;
  911 found:
  912         /* If writing isn't allowed */
  913         if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
  914                             ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) {
  915                 return (EPERM);
  916         }
  917 
  918         /*
  919          * If we're inside the kernel, the OID must be marked as kernel-valid.
  920          * XXX This mechanism for testing is bad.
  921          */
  922         if ((req->oldfunc == sysctl_old_kernel) && !(oid->oid_kind & CTLFLAG_KERN))
  923                 return(EPERM);
  924 
  925         /* Most likely only root can write */
  926         if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
  927             req->newptr && req->p &&
  928             (error = suser(req->p->p_ucred, &req->p->p_acflag)))
  929                 return (error);
  930 
  931         if (!oid->oid_handler) {
  932             return EINVAL;
  933         }
  934 
  935         /*
  936          * Switch to the NETWORK funnel for CTL_NET and KERN_IPC sysctls
  937          */
  938 
  939         if (((name[0] == CTL_NET) || ((name[0] == CTL_KERN) &&
  940                                                        (name[1] == KERN_IPC))))
  941              thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
  942 
  943         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  944                 i = (oid->oid_handler) (oid,
  945                                         name + indx, namelen - indx,
  946                                         req);
  947         } else {
  948                 i = (oid->oid_handler) (oid,
  949                                         oid->oid_arg1, oid->oid_arg2,
  950                                         req);
  951         }
  952 
  953         /*
  954          * Switch back to the KERNEL funnel, if necessary
  955          */
  956 
  957         if (((name[0] == CTL_NET) || ((name[0] == CTL_KERN) &&
  958                                                        (name[1] == KERN_IPC))))
  959              thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
  960 
  961         return (i);
  962 }
  963 
  964 #ifndef _SYS_SYSPROTO_H_
  965 struct sysctl_args {
  966         int     *name;
  967         u_int   namelen;
  968         void    *old;
  969         size_t  *oldlenp;
  970         void    *new;
  971         size_t  newlen;
  972 };
  973 #endif
  974 
  975 int
  976 /* __sysctl(struct proc *p, struct sysctl_args *uap) */
  977 new_sysctl(struct proc *p, struct sysctl_args *uap)
  978 {
  979         int error, i, name[CTL_MAXNAME];
  980         size_t j;
  981 
  982         if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
  983                 return (EINVAL);
  984 
  985         error = copyin(uap->name, &name, uap->namelen * sizeof(int));
  986         if (error)
  987                 return (error);
  988 
  989         error = userland_sysctl(p, name, uap->namelen,
  990                 uap->old, uap->oldlenp, 0,
  991                 uap->new, uap->newlen, &j);
  992         if (error && error != ENOMEM)
  993                 return (error);
  994         if (uap->oldlenp) {
  995                 i = copyout(&j, uap->oldlenp, sizeof(j));
  996                 if (i)
  997                         return (i);
  998         }
  999         return (error);
 1000 }
 1001 
 1002 /*
 1003  * This is used from various compatibility syscalls too.  That's why name
 1004  * must be in kernel space.
 1005  */
 1006 int
 1007 userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
 1008 {
 1009         int error = 0;
 1010         struct sysctl_req req, req2;
 1011 
 1012         bzero(&req, sizeof req);
 1013 
 1014         req.p = p;
 1015 
 1016         if (oldlenp) {
 1017                 if (inkernel) {
 1018                         req.oldlen = *oldlenp;
 1019                 } else {
 1020                         error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
 1021                         if (error)
 1022                                 return (error);
 1023                 }
 1024         }
 1025 
 1026         if (old) {
 1027                 req.oldptr= old;
 1028         }
 1029 
 1030         if (newlen) {
 1031                 req.newlen = newlen;
 1032                 req.newptr = new;
 1033         }
 1034 
 1035         req.oldfunc = sysctl_old_user;
 1036         req.newfunc = sysctl_new_user;
 1037         req.lock = 1;
 1038 
 1039         do {
 1040             req2 = req;
 1041             error = sysctl_root(0, name, namelen, &req2);
 1042         } while (error == EAGAIN);
 1043 
 1044         req = req2;
 1045 
 1046         if (error && error != ENOMEM)
 1047                 return (error);
 1048 
 1049         if (retval) {
 1050                 if (req.oldptr && req.oldidx > req.oldlen)
 1051                         *retval = req.oldlen;
 1052                 else
 1053                         *retval = req.oldidx;
 1054         }
 1055         return (error);
 1056 }
 1057 
 1058 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
 1059 #define KINFO_BSDI_SYSINFO      (101<<8)
 1060 
 1061 /*
 1062  * Kernel versions of the userland sysctl helper functions.
 1063  *
 1064  * These allow sysctl to be used in the same fashion in both
 1065  * userland and the kernel.
 1066  *
 1067  * Note that some sysctl handlers use copyin/copyout, which
 1068  * may not work correctly.
 1069  */
 1070 
 1071 static int
 1072 sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
 1073 {
 1074 
 1075         return(kernel_sysctl(current_proc(), name, namelen, oldp, oldlenp, newp, newlen));
 1076 }
 1077 
 1078 static int
 1079 sysctlnametomib(const char *name, int *mibp, size_t *sizep)
 1080 {
 1081         int oid[2];
 1082         int error;
 1083 
 1084         /* magic service node */
 1085         oid[0] = 0;
 1086         oid[1] = 3;
 1087 
 1088         /* look up OID for name */
 1089         *sizep *= sizeof(int);
 1090         error = sysctl(oid, 2, mibp, sizep, (void *)name, strlen(name));
 1091         *sizep /= sizeof(int);
 1092         return(error);
 1093 }
 1094 
 1095 int
 1096 sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
 1097 {
 1098         int oid[CTL_MAXNAME + 2];
 1099         int error;
 1100         size_t oidlen;
 1101 
 1102         /* look up the OID */
 1103         oidlen = CTL_MAXNAME;
 1104         error = sysctlnametomib(name, oid, &oidlen);
 1105 
 1106         /* now use the OID */
 1107         if (error == 0)
 1108                 error = sysctl(oid, oidlen, oldp, oldlenp, newp, newlen);
 1109         return(error);
 1110 }
 1111 

Cache object: 914fc42da65dc96a03c4b1607c16af84


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