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


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

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

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

    1 /*-
    2  * Copyright (c) 1982, 1986, 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Mike Karels at Berkeley Software Design, Inc.
    7  *
    8  * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
    9  * project, to make these variables more userfriendly.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the University of
   22  *      California, Berkeley and its contributors.
   23  * 4. Neither the name of the University nor the names of its contributors
   24  *    may be used to endorse or promote products derived from this software
   25  *    without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   37  * SUCH DAMAGE.
   38  *
   39  *      @(#)kern_sysctl.c       8.4 (Berkeley) 4/14/94
   40  * $FreeBSD$
   41  */
   42 
   43 #include "opt_compat.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/buf.h>
   47 #include <sys/kernel.h>
   48 #include <sys/sysctl.h>
   49 #include <sys/malloc.h>
   50 #include <sys/proc.h>
   51 #include <sys/systm.h>
   52 #include <sys/sysproto.h>
   53 #include <vm/vm.h>
   54 #include <vm/vm_extern.h>
   55 
   56 static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
   57 
   58 /*
   59  * Locking and stats
   60  */
   61 static struct sysctl_lock {
   62         int     sl_lock;
   63         int     sl_want;
   64         int     sl_locked;
   65 } memlock;
   66 
   67 static int sysctl_root SYSCTL_HANDLER_ARGS;
   68 
   69 extern struct linker_set sysctl_;
   70 
   71 /*
   72  * Initialization of the MIB tree.
   73  *
   74  * Order by number in each linker_set.
   75  */
   76 
   77 static int
   78 sysctl_order_cmp(const void *a, const void *b)
   79 {
   80         struct sysctl_oid const * const *pa;
   81         struct sysctl_oid const * const *pb;
   82 
   83         pa = (struct sysctl_oid const * const *)a;
   84         pb = (struct sysctl_oid const * const *)b;
   85         if (*pa == NULL && *pb == NULL)
   86                 return 0;
   87         if (*pa == NULL)
   88                 return (1);
   89         if (*pb == NULL)
   90                 return (-1);
   91         return ((*pa)->oid_number - (*pb)->oid_number);
   92 }
   93 
   94 static void
   95 sysctl_order(void *arg)
   96 {
   97         int j, k;
   98         struct linker_set *l = (struct linker_set *) arg;
   99         struct sysctl_oid **oidpp;
  100 
  101         /* First, find the highest oid we have */
  102         j = l->ls_length;
  103         oidpp = (struct sysctl_oid **) l->ls_items;
  104         for (k = 0; j--; oidpp++) {
  105                 if (!*oidpp)
  106                         continue;
  107                 if ((*oidpp)->oid_arg1 == arg) {
  108                         *oidpp = 0;
  109                         continue;
  110                 }
  111                 if ((*oidpp)->oid_number > k)
  112                         k = (*oidpp)->oid_number;
  113         }
  114 
  115         /* Next, replace all OID_AUTO oids with new numbers */
  116         j = l->ls_length;
  117         oidpp = (struct sysctl_oid **) l->ls_items;
  118         k += 100;
  119         for (; j--; oidpp++) 
  120                 if (*oidpp && (*oidpp)->oid_number == OID_AUTO)
  121                         (*oidpp)->oid_number = k++;
  122 
  123         /* Finally: sort by oid */
  124         j = l->ls_length;
  125         oidpp = (struct sysctl_oid **) l->ls_items;
  126         for (; j--; oidpp++) {
  127                 if (!*oidpp)
  128                         continue;
  129                 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
  130                         if (!(*oidpp)->oid_handler)
  131                                 sysctl_order((*oidpp)->oid_arg1);
  132         }
  133         qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
  134                 sysctl_order_cmp);
  135 }
  136 
  137 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
  138 
  139 void
  140 sysctl_order_all(void)
  141 {
  142         sysctl_order(&sysctl_);
  143 }
  144 
  145 /*
  146  * "Staff-functions"
  147  *
  148  * These functions implement a presently undocumented interface 
  149  * used by the sysctl program to walk the tree, and get the type
  150  * so it can print the value.
  151  * This interface is under work and consideration, and should probably
  152  * be killed with a big axe by the first person who can find the time.
  153  * (be aware though, that the proper interface isn't as obvious as it
  154  * may seem, there are various conflicting requirements.
  155  *
  156  * {0,0}        printf the entire MIB-tree.
  157  * {0,1,...}    return the name of the "..." OID.
  158  * {0,2,...}    return the next OID.
  159  * {0,3}        return the OID of the name in "new"
  160  * {0,4,...}    return the kind & format info for the "..." OID.
  161  */
  162 
  163 static void
  164 sysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
  165 {
  166         int j, k;
  167         struct sysctl_oid **oidpp;
  168 
  169         j = l->ls_length;
  170         oidpp = (struct sysctl_oid **) l->ls_items;
  171         for (; j--; oidpp++) {
  172 
  173                 if (!*oidpp)
  174                         continue;
  175 
  176                 for (k=0; k<i; k++)
  177                         printf(" ");
  178 
  179                 printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
  180 
  181                 printf("%c%c",
  182                         (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
  183                         (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
  184 
  185                 if ((*oidpp)->oid_handler)
  186                         printf(" *Handler");
  187 
  188                 switch ((*oidpp)->oid_kind & CTLTYPE) {
  189                         case CTLTYPE_NODE:
  190                                 printf(" Node\n");
  191                                 if (!(*oidpp)->oid_handler) {
  192                                         sysctl_sysctl_debug_dump_node(
  193                                                 (*oidpp)->oid_arg1, i+2);
  194                                 }
  195                                 break;
  196                         case CTLTYPE_INT:    printf(" Int\n"); break;
  197                         case CTLTYPE_STRING: printf(" String\n"); break;
  198                         case CTLTYPE_QUAD:   printf(" Quad\n"); break;
  199                         case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
  200                         default:             printf("\n");
  201                 }
  202 
  203         }
  204 }
  205 
  206 static int
  207 sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
  208 {
  209         sysctl_sysctl_debug_dump_node(&sysctl_, 0);
  210         return ENOENT;
  211 }
  212 
  213 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
  214         0, 0, sysctl_sysctl_debug, "-", "");
  215 
  216 static int
  217 sysctl_sysctl_name SYSCTL_HANDLER_ARGS
  218 {
  219         int *name = (int *) arg1;
  220         u_int namelen = arg2;
  221         int i, j, error = 0;
  222         struct sysctl_oid **oidpp;
  223         struct linker_set *lsp = &sysctl_;
  224         char buf[10];
  225 
  226         while (namelen) {
  227                 if (!lsp) {
  228                         snprintf(buf,sizeof(buf),"%d",*name);
  229                         if (req->oldidx)
  230                                 error = SYSCTL_OUT(req, ".", 1);
  231                         if (!error)
  232                                 error = SYSCTL_OUT(req, buf, strlen(buf));
  233                         if (error)
  234                                 return (error);
  235                         namelen--;
  236                         name++;
  237                         continue;
  238                 }
  239                 oidpp = (struct sysctl_oid **) lsp->ls_items;
  240                 j = lsp->ls_length;
  241                 lsp = 0;
  242                 for (i = 0; i < j; i++, oidpp++) {
  243                         if (*oidpp && ((*oidpp)->oid_number != *name))
  244                                 continue;
  245 
  246                         if (req->oldidx)
  247                                 error = SYSCTL_OUT(req, ".", 1);
  248                         if (!error)
  249                                 error = SYSCTL_OUT(req, (*oidpp)->oid_name,
  250                                         strlen((*oidpp)->oid_name));
  251                         if (error)
  252                                 return (error);
  253 
  254                         namelen--;
  255                         name++;
  256 
  257                         if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  258                                 break;
  259 
  260                         if ((*oidpp)->oid_handler)
  261                                 break;
  262 
  263                         lsp = (struct linker_set*)(*oidpp)->oid_arg1;
  264                         break;
  265                 }
  266         }
  267         return (SYSCTL_OUT(req, "", 1));
  268 }
  269 
  270 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
  271 
  272 static int
  273 sysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen, 
  274         int *next, int *len, int level, struct sysctl_oid **oidp)
  275 {
  276         int i, j;
  277         struct sysctl_oid **oidpp;
  278 
  279         oidpp = (struct sysctl_oid **) lsp->ls_items;
  280         j = lsp->ls_length;
  281         *len = level;
  282         for (i = 0; i < j; i++, oidpp++) {
  283                 if (!*oidpp)
  284                         continue;
  285 
  286                 *next = (*oidpp)->oid_number;
  287                 *oidp = *oidpp;
  288 
  289                 if (!namelen) {
  290                         if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 
  291                                 return 0;
  292                         if ((*oidpp)->oid_handler) 
  293                                 /* We really should call the handler here...*/
  294                                 return 0;
  295                         lsp = (struct linker_set*)(*oidpp)->oid_arg1;
  296                         if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1, 
  297                                 len, level+1, oidp))
  298                                 return 0;
  299                         goto next;
  300                 }
  301 
  302                 if ((*oidpp)->oid_number < *name)
  303                         continue;
  304 
  305                 if ((*oidpp)->oid_number > *name) {
  306                         if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  307                                 return 0;
  308                         if ((*oidpp)->oid_handler)
  309                                 return 0;
  310                         lsp = (struct linker_set*)(*oidpp)->oid_arg1;
  311                         if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, 
  312                                 next+1, len, level+1, oidp))
  313                                 return (0);
  314                         goto next;
  315                 }
  316                 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  317                         continue;
  318 
  319                 if ((*oidpp)->oid_handler)
  320                         continue;
  321 
  322                 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
  323                 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1, 
  324                         len, level+1, oidp))
  325                         return (0);
  326         next:
  327                 namelen = 1;
  328                 *len = level;
  329         }
  330         return 1;
  331 }
  332 
  333 static int
  334 sysctl_sysctl_next SYSCTL_HANDLER_ARGS
  335 {
  336         int *name = (int *) arg1;
  337         u_int namelen = arg2;
  338         int i, j, error;
  339         struct sysctl_oid *oid;
  340         struct linker_set *lsp = &sysctl_;
  341         int newoid[CTL_MAXNAME];
  342 
  343         i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
  344         if (i)
  345                 return ENOENT;
  346         error = SYSCTL_OUT(req, newoid, j * sizeof (int));
  347         return (error);
  348 }
  349 
  350 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
  351 
  352 static int
  353 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidp)
  354 {
  355         int i, j;
  356         struct sysctl_oid **oidpp;
  357         struct linker_set *lsp = &sysctl_;
  358         char *p;
  359 
  360         if (!*name)
  361                 return ENOENT;
  362 
  363         p = name + strlen(name) - 1 ;
  364         if (*p == '.')
  365                 *p = '\0';
  366 
  367         *len = 0;
  368 
  369         for (p = name; *p && *p != '.'; p++) 
  370                 ;
  371         i = *p;
  372         if (i == '.')
  373                 *p = '\0';
  374 
  375         j = lsp->ls_length;
  376         oidpp = (struct sysctl_oid **) lsp->ls_items;
  377 
  378         while (j-- && *len < CTL_MAXNAME) {
  379                 if (!*oidpp)
  380                         continue;
  381                 if (strcmp(name, (*oidpp)->oid_name)) {
  382                         oidpp++;
  383                         continue;
  384                 }
  385                 *oid++ = (*oidpp)->oid_number;
  386                 (*len)++;
  387 
  388                 if (!i) {
  389                         if (oidp)
  390                                 *oidp = *oidpp;
  391                         return (0);
  392                 }
  393 
  394                 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  395                         break;
  396 
  397                 if ((*oidpp)->oid_handler)
  398                         break;
  399 
  400                 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
  401                 j = lsp->ls_length;
  402                 oidpp = (struct sysctl_oid **)lsp->ls_items;
  403                 name = p+1;
  404                 for (p = name; *p && *p != '.'; p++) 
  405                                 ;
  406                 i = *p;
  407                 if (i == '.')
  408                         *p = '\0';
  409         }
  410         return ENOENT;
  411 }
  412 
  413 static int
  414 sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
  415 {
  416         char *p;
  417         int error, oid[CTL_MAXNAME], len;
  418         struct sysctl_oid *op = 0;
  419 
  420         if (!req->newlen) 
  421                 return ENOENT;
  422         if (req->newlen >= MAXPATHLEN)  /* XXX arbitrary, undocumented */
  423                 return (ENAMETOOLONG);
  424 
  425         p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
  426 
  427         error = SYSCTL_IN(req, p, req->newlen);
  428         if (error) {
  429                 free(p, M_SYSCTL);
  430                 return (error);
  431         }
  432 
  433         p [req->newlen] = '\0';
  434 
  435         error = name2oid(p, oid, &len, &op);
  436 
  437         free(p, M_SYSCTL);
  438 
  439         if (error)
  440                 return (error);
  441 
  442         error = SYSCTL_OUT(req, oid, len * sizeof *oid);
  443         return (error);
  444 }
  445 
  446 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 
  447         sysctl_sysctl_name2oid, "I", "");
  448 
  449 static int
  450 sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
  451 {
  452         int *name = (int *) arg1, error;
  453         u_int namelen = arg2;
  454         int indx, j;
  455         struct sysctl_oid **oidpp;
  456         struct linker_set *lsp = &sysctl_;
  457 
  458         j = lsp->ls_length;
  459         oidpp = (struct sysctl_oid **) lsp->ls_items;
  460 
  461         indx = 0;
  462         while (j-- && indx < CTL_MAXNAME) {
  463                 if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
  464                         indx++;
  465                         if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  466                                 if ((*oidpp)->oid_handler)
  467                                         goto found;
  468                                 if (indx == namelen)
  469                                         goto found;
  470                                 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
  471                                 j = lsp->ls_length;
  472                                 oidpp = (struct sysctl_oid **)lsp->ls_items;
  473                         } else {
  474                                 if (indx != namelen)
  475                                         return EISDIR;
  476                                 goto found;
  477                         }
  478                 } else {
  479                         oidpp++;
  480                 }
  481         }
  482         return ENOENT;
  483 found:
  484         if (!(*oidpp)->oid_fmt)
  485                 return ENOENT;
  486         error = SYSCTL_OUT(req, 
  487                 &(*oidpp)->oid_kind, sizeof((*oidpp)->oid_kind));
  488         if (!error)
  489                 error = SYSCTL_OUT(req, (*oidpp)->oid_fmt, 
  490                         strlen((*oidpp)->oid_fmt)+1);
  491         return (error);
  492 }
  493 
  494 
  495 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
  496 
  497 /*
  498  * Default "handler" functions.
  499  */
  500 
  501 /*
  502  * Handle an int, signed or unsigned.
  503  * Two cases:
  504  *     a variable:  point arg1 at it.
  505  *     a constant:  pass it in arg2.
  506  */
  507 
  508 int
  509 sysctl_handle_int SYSCTL_HANDLER_ARGS
  510 {
  511         int error = 0;
  512 
  513         if (arg1)
  514                 error = SYSCTL_OUT(req, arg1, sizeof(int));
  515         else
  516                 error = SYSCTL_OUT(req, &arg2, sizeof(int));
  517 
  518         if (error || !req->newptr)
  519                 return (error);
  520 
  521         if (!arg1)
  522                 error = EPERM;
  523         else
  524                 error = SYSCTL_IN(req, arg1, sizeof(int));
  525         return (error);
  526 }
  527 
  528 /*
  529  * Handle a long, signed or unsigned.  arg1 points to it.
  530  */
  531 
  532 int
  533 sysctl_handle_long SYSCTL_HANDLER_ARGS
  534 {
  535         int error = 0;
  536 
  537         if (!arg1)
  538                 return (EINVAL);
  539         error = SYSCTL_OUT(req, arg1, sizeof(long));
  540 
  541         if (error || !req->newptr)
  542                 return (error);
  543 
  544         error = SYSCTL_IN(req, arg1, sizeof(long));
  545         return (error);
  546 }
  547 
  548 /*
  549  * Handle our generic '\0' terminated 'C' string.
  550  * Two cases:
  551  *      a variable string:  point arg1 at it, arg2 is max length.
  552  *      a constant string:  point arg1 at it, arg2 is zero.
  553  */
  554 
  555 int
  556 sysctl_handle_string SYSCTL_HANDLER_ARGS
  557 {
  558         int error=0;
  559 
  560         error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
  561 
  562         if (error || !req->newptr)
  563                 return (error);
  564 
  565         if ((req->newlen - req->newidx) >= arg2) {
  566                 error = EINVAL;
  567         } else {
  568                 arg2 = (req->newlen - req->newidx);
  569                 error = SYSCTL_IN(req, arg1, arg2);
  570                 ((char *)arg1)[arg2] = '\0';
  571         }
  572 
  573         return (error);
  574 }
  575 
  576 /*
  577  * Handle any kind of opaque data.
  578  * arg1 points to it, arg2 is the size.
  579  */
  580 
  581 int
  582 sysctl_handle_opaque SYSCTL_HANDLER_ARGS
  583 {
  584         int error;
  585 
  586         error = SYSCTL_OUT(req, arg1, arg2);
  587 
  588         if (error || !req->newptr)
  589                 return (error);
  590 
  591         error = SYSCTL_IN(req, arg1, arg2);
  592 
  593         return (error);
  594 }
  595 
  596 /*
  597  * Transfer functions to/from kernel space.
  598  * XXX: rather untested at this point
  599  */
  600 static int
  601 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
  602 {
  603         size_t i = 0;
  604 
  605         if (req->oldptr) {
  606                 i = l;
  607                 if (i > req->oldlen - req->oldidx)
  608                         i = req->oldlen - req->oldidx;
  609                 if (i > 0)
  610                         bcopy(p, (char *)req->oldptr + req->oldidx, i);
  611         }
  612         req->oldidx += l;
  613         if (req->oldptr && i != l)
  614                 return (ENOMEM);
  615         return (0);
  616 }
  617 
  618 static int
  619 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
  620 {
  621         if (!req->newptr)
  622                 return 0;
  623         if (req->newlen - req->newidx < l)
  624                 return (EINVAL);
  625         bcopy((char *)req->newptr + req->newidx, p, l);
  626         req->newidx += l;
  627         return (0);
  628 }
  629 
  630 int
  631 kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
  632 {
  633         int error = 0;
  634         struct sysctl_req req;
  635 
  636         bzero(&req, sizeof req);
  637 
  638         req.p = p;
  639 
  640         if (oldlenp) {
  641                 req.oldlen = *oldlenp;
  642         }
  643 
  644         if (old) {
  645                 req.oldptr= old;
  646         }
  647 
  648         if (newlen) {
  649                 req.newlen = newlen;
  650                 req.newptr = new;
  651         }
  652 
  653         req.oldfunc = sysctl_old_kernel;
  654         req.newfunc = sysctl_new_kernel;
  655         req.lock = 1;
  656 
  657         /* XXX this should probably be done in a general way */
  658         while (memlock.sl_lock) {
  659                 memlock.sl_want = 1;
  660                 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
  661                 memlock.sl_locked++;
  662         }
  663         memlock.sl_lock = 1;
  664 
  665         error = sysctl_root(0, name, namelen, &req);
  666 
  667         if (req.lock == 2)
  668                 vsunlock(req.oldptr, req.oldlen, B_WRITE);
  669 
  670         memlock.sl_lock = 0;
  671 
  672         if (memlock.sl_want) {
  673                 memlock.sl_want = 0;
  674                 wakeup((caddr_t)&memlock);
  675         }
  676 
  677         if (error && error != ENOMEM)
  678                 return (error);
  679 
  680         if (retval) {
  681                 if (req.oldptr && req.oldidx > req.oldlen)
  682                         *retval = req.oldlen;
  683                 else
  684                         *retval = req.oldidx;
  685         }
  686         return (error);
  687 }
  688 
  689 /*
  690  * Transfer function to/from user space.
  691  */
  692 static int
  693 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
  694 {
  695         int error = 0;
  696         size_t i = 0;
  697 
  698         if (req->lock == 1 && req->oldptr) {
  699                 vslock(req->oldptr, req->oldlen);
  700                 req->lock = 2;
  701         }
  702         if (req->oldptr) {
  703                 i = l;
  704                 if (i > req->oldlen - req->oldidx)
  705                         i = req->oldlen - req->oldidx;
  706                 if (i > 0)
  707                         error = copyout(p, (char *)req->oldptr + req->oldidx,
  708                                         i);
  709         }
  710         req->oldidx += l;
  711         if (error)
  712                 return (error);
  713         if (req->oldptr && i < l)
  714                 return (ENOMEM);
  715         return (0);
  716 }
  717 
  718 static int
  719 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
  720 {
  721         int error;
  722 
  723         if (!req->newptr)
  724                 return 0;
  725         if (req->newlen - req->newidx < l)
  726                 return (EINVAL);
  727         error = copyin((char *)req->newptr + req->newidx, p, l);
  728         req->newidx += l;
  729         return (error);
  730 }
  731 
  732 /*
  733  * Traverse our tree, and find the right node, execute whatever it points
  734  * at, and return the resulting error code.
  735  */
  736 
  737 int
  738 sysctl_root SYSCTL_HANDLER_ARGS
  739 {
  740         int *name = (int *) arg1;
  741         u_int namelen = arg2;
  742         int indx, i, j;
  743         struct sysctl_oid **oidpp;
  744         struct linker_set *lsp = &sysctl_;
  745 
  746         j = lsp->ls_length;
  747         oidpp = (struct sysctl_oid **) lsp->ls_items;
  748 
  749         indx = 0;
  750         while (j-- && indx < CTL_MAXNAME) {
  751                 if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
  752                         indx++;
  753                         if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
  754                                 req->lock = 0;
  755                         if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  756                                 if ((*oidpp)->oid_handler)
  757                                         goto found;
  758                                 if (indx == namelen)
  759                                         return ENOENT;
  760                                 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
  761                                 j = lsp->ls_length;
  762                                 oidpp = (struct sysctl_oid **)lsp->ls_items;
  763                         } else {
  764                                 if (indx != namelen)
  765                                         return EISDIR;
  766                                 goto found;
  767                         }
  768                 } else {
  769                         oidpp++;
  770                 }
  771         }
  772         return ENOENT;
  773 found:
  774         /* If writing isn't allowed */
  775         if (req->newptr && (!((*oidpp)->oid_kind & CTLFLAG_WR) ||
  776             (((*oidpp)->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
  777                 return (EPERM);
  778 
  779         /* Most likely only root can write */
  780         if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
  781             req->newptr && req->p &&
  782             (i = suser(req->p->p_ucred, &req->p->p_acflag)))
  783                 return (i);
  784 
  785         if (!(*oidpp)->oid_handler)
  786                 return EINVAL;
  787 
  788         if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  789                 i = ((*oidpp)->oid_handler) (*oidpp,
  790                                         name + indx, namelen - indx,
  791                                         req);
  792         } else {
  793                 i = ((*oidpp)->oid_handler) (*oidpp,
  794                                         (*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
  795                                         req);
  796         }
  797         return (i);
  798 }
  799 
  800 #ifndef _SYS_SYSPROTO_H_
  801 struct sysctl_args {
  802         int     *name;
  803         u_int   namelen;
  804         void    *old;
  805         size_t  *oldlenp;
  806         void    *new;
  807         size_t  newlen;
  808 };
  809 #endif
  810 
  811 int
  812 __sysctl(struct proc *p, struct sysctl_args *uap)
  813 {
  814         int error, i, name[CTL_MAXNAME];
  815         size_t j;
  816 
  817         if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
  818                 return (EINVAL);
  819 
  820         error = copyin(uap->name, &name, uap->namelen * sizeof(int));
  821         if (error)
  822                 return (error);
  823 
  824         error = userland_sysctl(p, name, uap->namelen,
  825                 uap->old, uap->oldlenp, 0,
  826                 uap->new, uap->newlen, &j);
  827         if (error && error != ENOMEM)
  828                 return (error);
  829         if (uap->oldlenp) {
  830                 i = copyout(&j, uap->oldlenp, sizeof(j));
  831                 if (i)
  832                         return (i);
  833         }
  834         return (error);
  835 }
  836 
  837 /*
  838  * This is used from various compatibility syscalls too.  That's why name
  839  * must be in kernel space.
  840  */
  841 int
  842 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)
  843 {
  844         int error = 0;
  845         struct sysctl_req req, req2;
  846 
  847         bzero(&req, sizeof req);
  848 
  849         req.p = p;
  850 
  851         if (oldlenp) {
  852                 if (inkernel) {
  853                         req.oldlen = *oldlenp;
  854                 } else {
  855                         error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
  856                         if (error)
  857                                 return (error);
  858                 }
  859         }
  860 
  861         if (old) {
  862                 if (!useracc(old, req.oldlen, B_WRITE))
  863                         return (EFAULT);
  864                 req.oldptr= old;
  865         }
  866 
  867         if (newlen) {
  868                 if (!useracc(new, req.newlen, B_READ))
  869                         return (EFAULT);
  870                 req.newlen = newlen;
  871                 req.newptr = new;
  872         }
  873 
  874         req.oldfunc = sysctl_old_user;
  875         req.newfunc = sysctl_new_user;
  876         req.lock = 1;
  877 
  878         /* XXX this should probably be done in a general way */
  879         while (memlock.sl_lock) {
  880                 memlock.sl_want = 1;
  881                 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
  882                 memlock.sl_locked++;
  883         }
  884         memlock.sl_lock = 1;
  885 
  886         do {
  887             req2 = req;
  888             error = sysctl_root(0, name, namelen, &req2);
  889         } while (error == EAGAIN);
  890 
  891         req = req2;
  892         if (req.lock == 2)
  893                 vsunlock(req.oldptr, req.oldlen, B_WRITE);
  894 
  895         memlock.sl_lock = 0;
  896 
  897         if (memlock.sl_want) {
  898                 memlock.sl_want = 0;
  899                 wakeup((caddr_t)&memlock);
  900         }
  901 
  902         if (error && error != ENOMEM)
  903                 return (error);
  904 
  905         if (retval) {
  906                 if (req.oldptr && req.oldidx > req.oldlen)
  907                         *retval = req.oldlen;
  908                 else
  909                         *retval = req.oldidx;
  910         }
  911         return (error);
  912 }
  913 
  914 #ifdef COMPAT_43
  915 #include <sys/socket.h>
  916 #include <vm/vm_param.h>
  917 
  918 #define KINFO_PROC              (0<<8)
  919 #define KINFO_RT                (1<<8)
  920 #define KINFO_VNODE             (2<<8)
  921 #define KINFO_FILE              (3<<8)
  922 #define KINFO_METER             (4<<8)
  923 #define KINFO_LOADAVG           (5<<8)
  924 #define KINFO_CLOCKRATE         (6<<8)
  925 
  926 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
  927 #define KINFO_BSDI_SYSINFO      (101<<8)
  928 
  929 /*
  930  * XXX this is bloat, but I hope it's better here than on the potentially
  931  * limited kernel stack...  -Peter
  932  */
  933 
  934 static struct {
  935         int     bsdi_machine;           /* "i386" on BSD/386 */
  936 /*      ^^^ this is an offset to the string, relative to the struct start */
  937         char    *pad0;
  938         long    pad1;
  939         long    pad2;
  940         long    pad3;
  941         u_long  pad4;
  942         u_long  pad5;
  943         u_long  pad6;
  944 
  945         int     bsdi_ostype;            /* "BSD/386" on BSD/386 */
  946         int     bsdi_osrelease;         /* "1.1" on BSD/386 */
  947         long    pad7;
  948         long    pad8;
  949         char    *pad9;
  950 
  951         long    pad10;
  952         long    pad11;
  953         int     pad12;
  954         long    pad13;
  955         quad_t  pad14;
  956         long    pad15;
  957 
  958         struct  timeval pad16;
  959         /* we dont set this, because BSDI's uname used gethostname() instead */
  960         int     bsdi_hostname;          /* hostname on BSD/386 */
  961 
  962         /* the actual string data is appended here */
  963 
  964 } bsdi_si;
  965 /*
  966  * this data is appended to the end of the bsdi_si structure during copyout.
  967  * The "char *" offsets are relative to the base of the bsdi_si struct.
  968  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
  969  * should not exceed the length of the buffer here... (or else!! :-)
  970  */
  971 static char bsdi_strings[80];   /* It had better be less than this! */
  972 
  973 #ifndef _SYS_SYSPROTO_H_
  974 struct getkerninfo_args {
  975         int     op;
  976         char    *where;
  977         size_t  *size;
  978         int     arg;
  979 };
  980 #endif
  981 
  982 int
  983 ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
  984 {
  985         int error, name[6];
  986         size_t size;
  987 
  988         switch (uap->op & 0xff00) {
  989 
  990         case KINFO_RT:
  991                 name[0] = CTL_NET;
  992                 name[1] = PF_ROUTE;
  993                 name[2] = 0;
  994                 name[3] = (uap->op & 0xff0000) >> 16;
  995                 name[4] = uap->op & 0xff;
  996                 name[5] = uap->arg;
  997                 error = userland_sysctl(p, name, 6, uap->where, uap->size,
  998                         0, 0, 0, &size);
  999                 break;
 1000 
 1001         case KINFO_VNODE:
 1002                 name[0] = CTL_KERN;
 1003                 name[1] = KERN_VNODE;
 1004                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1005                         0, 0, 0, &size);
 1006                 break;
 1007 
 1008         case KINFO_PROC:
 1009                 name[0] = CTL_KERN;
 1010                 name[1] = KERN_PROC;
 1011                 name[2] = uap->op & 0xff;
 1012                 name[3] = uap->arg;
 1013                 error = userland_sysctl(p, name, 4, uap->where, uap->size,
 1014                         0, 0, 0, &size);
 1015                 break;
 1016 
 1017         case KINFO_FILE:
 1018                 name[0] = CTL_KERN;
 1019                 name[1] = KERN_FILE;
 1020                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1021                         0, 0, 0, &size);
 1022                 break;
 1023 
 1024         case KINFO_METER:
 1025                 name[0] = CTL_VM;
 1026                 name[1] = VM_METER;
 1027                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1028                         0, 0, 0, &size);
 1029                 break;
 1030 
 1031         case KINFO_LOADAVG:
 1032                 name[0] = CTL_VM;
 1033                 name[1] = VM_LOADAVG;
 1034                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1035                         0, 0, 0, &size);
 1036                 break;
 1037 
 1038         case KINFO_CLOCKRATE:
 1039                 name[0] = CTL_KERN;
 1040                 name[1] = KERN_CLOCKRATE;
 1041                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1042                         0, 0, 0, &size);
 1043                 break;
 1044 
 1045         case KINFO_BSDI_SYSINFO: {
 1046                 /*
 1047                  * this is pretty crude, but it's just enough for uname()
 1048                  * from BSDI's 1.x libc to work.
 1049                  *
 1050                  * In particular, it doesn't return the same results when
 1051                  * the supplied buffer is too small.  BSDI's version apparently
 1052                  * will return the amount copied, and set the *size to how
 1053                  * much was needed.  The emulation framework here isn't capable
 1054                  * of that, so we just set both to the amount copied.
 1055                  * BSDI's 2.x product apparently fails with ENOMEM in this
 1056                  * scenario.
 1057                  */
 1058 
 1059                 u_int needed;
 1060                 u_int left;
 1061                 char *s;
 1062 
 1063                 bzero((char *)&bsdi_si, sizeof(bsdi_si));
 1064                 bzero(bsdi_strings, sizeof(bsdi_strings));
 1065 
 1066                 s = bsdi_strings;
 1067 
 1068                 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
 1069                 strcpy(s, ostype);
 1070                 s += strlen(s) + 1;
 1071 
 1072                 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
 1073                 strcpy(s, osrelease);
 1074                 s += strlen(s) + 1;
 1075 
 1076                 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
 1077                 strcpy(s, machine);
 1078                 s += strlen(s) + 1;
 1079 
 1080                 needed = sizeof(bsdi_si) + (s - bsdi_strings);
 1081 
 1082                 if (uap->where == NULL) {
 1083                         /* process is asking how much buffer to supply.. */
 1084                         size = needed;
 1085                         error = 0;
 1086                         break;
 1087                 }
 1088 
 1089 
 1090                 /* if too much buffer supplied, trim it down */
 1091                 if (size > needed)
 1092                         size = needed;
 1093 
 1094                 /* how much of the buffer is remaining */
 1095                 left = size;
 1096 
 1097                 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
 1098                         break;
 1099 
 1100                 /* is there any point in continuing? */
 1101                 if (left > sizeof(bsdi_si)) {
 1102                         left -= sizeof(bsdi_si);
 1103                         error = copyout(&bsdi_strings,
 1104                                         uap->where + sizeof(bsdi_si), left);
 1105                 }
 1106                 break;
 1107         }
 1108 
 1109         default:
 1110                 return (EOPNOTSUPP);
 1111         }
 1112         if (error)
 1113                 return (error);
 1114         p->p_retval[0] = size;
 1115         if (uap->size)
 1116                 error = copyout((caddr_t)&size, (caddr_t)uap->size,
 1117                     sizeof(size));
 1118         return (error);
 1119 }
 1120 #endif /* COMPAT_43 */

Cache object: c875418348217cdccd52fc8a22b6a562


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