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

Cache object: 523fd1ba0ff5eaca69ad5ceecc2abb97


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