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/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/buf.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/malloc.h>
   51 #include <sys/proc.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 static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
   58 
   59 /*
   60  * Locking and stats
   61  */
   62 static struct sysctl_lock {
   63         int     sl_lock;
   64         int     sl_want;
   65         int     sl_locked;
   66 } memlock;
   67 
   68 static int sysctl_root(SYSCTL_HANDLER_ARGS);
   69 
   70 struct sysctl_oid_list sysctl__children; /* root list */
   71 
   72 static struct sysctl_oid *
   73 sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
   74 {
   75         struct sysctl_oid *oidp;
   76 
   77         SLIST_FOREACH(oidp, list, oid_link) {
   78                 if (strcmp(oidp->oid_name, name) == 0) {
   79                         return (oidp);
   80                 }
   81         }
   82         return (NULL);
   83 }
   84 
   85 /*
   86  * Initialization of the MIB tree.
   87  *
   88  * Order by number in each list.
   89  */
   90 
   91 void sysctl_register_oid(struct sysctl_oid *oidp)
   92 {
   93         struct sysctl_oid_list *parent = oidp->oid_parent;
   94         struct sysctl_oid *p;
   95         struct sysctl_oid *q;
   96         int n;
   97 
   98         /*
   99          * First check if another oid with the same name already
  100          * exists in the parent's list.
  101          */
  102         p = sysctl_find_oidname(oidp->oid_name, parent);
  103         if (p != NULL) {
  104                 if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  105                         p->oid_refcnt++;
  106                         return;
  107                 } else {
  108                         printf("can't re-use a leaf (%s)!\n", p->oid_name);
  109                         return;
  110                 }
  111         }
  112         /*
  113          * If this oid has a number OID_AUTO, give it a number which
  114          * is greater than any current oid.  Make sure it is at least
  115          * 100 to leave space for pre-assigned oid numbers.
  116          */
  117         if (oidp->oid_number == OID_AUTO) {
  118                 /* First, find the highest oid in the parent list >99 */
  119                 n = 99;
  120                 SLIST_FOREACH(p, parent, oid_link) {
  121                         if (p->oid_number > n)
  122                                 n = p->oid_number;
  123                 }
  124                 oidp->oid_number = n + 1;
  125         }
  126 
  127         /*
  128          * Insert the oid into the parent's list in order.
  129          */
  130         q = NULL;
  131         SLIST_FOREACH(p, parent, oid_link) {
  132                 if (oidp->oid_number < p->oid_number)
  133                         break;
  134                 q = p;
  135         }
  136         if (q)
  137                 SLIST_INSERT_AFTER(q, oidp, oid_link);
  138         else
  139                 SLIST_INSERT_HEAD(parent, oidp, oid_link);
  140 }
  141 
  142 void sysctl_unregister_oid(struct sysctl_oid *oidp)
  143 {
  144 
  145         SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
  146 }
  147 
  148 /* Initialize a new context to keep track of dynamically added sysctls. */
  149 int
  150 sysctl_ctx_init(struct sysctl_ctx_list *c)
  151 {
  152 
  153         if (c == NULL) {
  154                 return (EINVAL);
  155         }
  156         TAILQ_INIT(c);
  157         return (0);
  158 }
  159 
  160 /* Free the context, and destroy all dynamic oids registered in this context */
  161 int
  162 sysctl_ctx_free(struct sysctl_ctx_list *clist)
  163 {
  164         struct sysctl_ctx_entry *e, *e1;
  165         int error;
  166 
  167         error = 0;
  168         /*
  169          * First perform a "dry run" to check if it's ok to remove oids.
  170          * XXX FIXME
  171          * XXX This algorithm is a hack. But I don't know any
  172          * XXX better solution for now...
  173          */
  174         TAILQ_FOREACH(e, clist, link) {
  175                 error = sysctl_remove_oid(e->entry, 0, 0);
  176                 if (error)
  177                         break;
  178         }
  179         /*
  180          * Restore deregistered entries, either from the end,
  181          * or from the place where error occured.
  182          * e contains the entry that was not unregistered
  183          */
  184         if (error)
  185                 e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
  186         else
  187                 e1 = TAILQ_LAST(clist, sysctl_ctx_list);
  188         while (e1 != NULL) {
  189                 sysctl_register_oid(e1->entry);
  190                 e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
  191         }
  192         if (error)
  193                 return(EBUSY);
  194         /* Now really delete the entries */
  195         e = TAILQ_FIRST(clist);
  196         while (e != NULL) {
  197                 e1 = TAILQ_NEXT(e, link);
  198                 error = sysctl_remove_oid(e->entry, 1, 0);
  199                 if (error)
  200                         panic("sysctl_remove_oid: corrupt tree, entry: %s",
  201                             e->entry->oid_name);
  202                 free(e, M_SYSCTLOID);
  203                 e = e1;
  204         }
  205         return (error);
  206 }
  207 
  208 /* Add an entry to the context */
  209 struct sysctl_ctx_entry *
  210 sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
  211 {
  212         struct sysctl_ctx_entry *e;
  213 
  214         if (clist == NULL || oidp == NULL)
  215                 return(NULL);
  216         e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
  217         e->entry = oidp;
  218         TAILQ_INSERT_HEAD(clist, e, link);
  219         return (e);
  220 }
  221 
  222 /* Find an entry in the context */
  223 struct sysctl_ctx_entry *
  224 sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
  225 {
  226         struct sysctl_ctx_entry *e;
  227 
  228         if (clist == NULL || oidp == NULL)
  229                 return(NULL);
  230         for (e = TAILQ_FIRST(clist); e != NULL; e = TAILQ_NEXT(e, link)) {
  231                 if(e->entry == oidp)
  232                         return(e);
  233         }
  234         return (e);
  235 }
  236 
  237 /*
  238  * Delete an entry from the context.
  239  * NOTE: this function doesn't free oidp! You have to remove it
  240  * with sysctl_remove_oid().
  241  */
  242 int
  243 sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
  244 {
  245         struct sysctl_ctx_entry *e;
  246 
  247         if (clist == NULL || oidp == NULL)
  248                 return (EINVAL);
  249         e = sysctl_ctx_entry_find(clist, oidp);
  250         if (e != NULL) {
  251                 TAILQ_REMOVE(clist, e, link);
  252                 free(e, M_SYSCTLOID);
  253                 return (0);
  254         } else
  255                 return (ENOENT);
  256 }
  257 
  258 /*
  259  * Remove dynamically created sysctl trees.
  260  * oidp - top of the tree to be removed
  261  * del - if 0 - just deregister, otherwise free up entries as well
  262  * recurse - if != 0 traverse the subtree to be deleted
  263  */
  264 int
  265 sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
  266 {
  267         struct sysctl_oid *p;
  268         int error;
  269 
  270         if (oidp == NULL)
  271                 return(EINVAL);
  272         if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
  273                 printf("can't remove non-dynamic nodes!\n");
  274                 return (EINVAL);
  275         }
  276         /*
  277          * WARNING: normal method to do this should be through
  278          * sysctl_ctx_free(). Use recursing as the last resort
  279          * method to purge your sysctl tree of leftovers...
  280          * However, if some other code still references these nodes,
  281          * it will panic.
  282          */
  283         if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  284                 if (oidp->oid_refcnt == 1) {
  285                         SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
  286                                 if (!recurse)
  287                                         return (ENOTEMPTY);
  288                                 error = sysctl_remove_oid(p, del, recurse);
  289                                 if (error)
  290                                         return (error);
  291                         }
  292                         if (del)
  293                                 free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
  294                 }
  295         }
  296         if (oidp->oid_refcnt > 1 ) {
  297                 oidp->oid_refcnt--;
  298         } else {
  299                 if (oidp->oid_refcnt == 0) {
  300                         printf("Warning: bad oid_refcnt=%u (%s)!\n",
  301                                 oidp->oid_refcnt, oidp->oid_name);
  302                         return (EINVAL);
  303                 }
  304                 sysctl_unregister_oid(oidp);
  305                 if (del) {
  306                         if (oidp->oid_descr)
  307                                 free((void *)(uintptr_t)(const void *)oidp->oid_descr, M_SYSCTLOID);
  308                         free((void *)(uintptr_t)(const void *)oidp->oid_name,
  309                              M_SYSCTLOID);
  310                         free(oidp, M_SYSCTLOID);
  311                 }
  312         }
  313         return (0);
  314 }
  315 
  316 /*
  317  * Create new sysctls at run time.
  318  * clist may point to a valid context initialized with sysctl_ctx_init().
  319  */
  320 struct sysctl_oid *
  321 sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
  322         int number, const char *name, int kind, void *arg1, int arg2,
  323         int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
  324 {
  325         struct sysctl_oid *oidp;
  326         ssize_t len;
  327         char *newname;
  328 
  329         /* You have to hook up somewhere.. */
  330         if (parent == NULL)
  331                 return(NULL);
  332         /* Check if the node already exists, otherwise create it */
  333         oidp = sysctl_find_oidname(name, parent);
  334         if (oidp != NULL) {
  335                 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
  336                         oidp->oid_refcnt++;
  337                         /* Update the context */
  338                         if (clist != NULL)
  339                                 sysctl_ctx_entry_add(clist, oidp);
  340                         return (oidp);
  341                 } else {
  342                         printf("can't re-use a leaf (%s)!\n", name);
  343                         return (NULL);
  344                 }
  345         }
  346         oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK);
  347         bzero(oidp, sizeof(struct sysctl_oid));
  348         oidp->oid_parent = parent;
  349         SLIST_NEXT(oidp, oid_link) = NULL;
  350         oidp->oid_number = number;
  351         oidp->oid_refcnt = 1;
  352         len = strlen(name);
  353         newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
  354         bcopy(name, newname, len + 1);
  355         newname[len] = '\0';
  356         oidp->oid_name = newname;
  357         oidp->oid_handler = handler;
  358         oidp->oid_kind = CTLFLAG_DYN | kind;
  359         if ((kind & CTLTYPE) == CTLTYPE_NODE) {
  360                 /* Allocate space for children */
  361                 SYSCTL_CHILDREN(oidp) = malloc(sizeof(struct sysctl_oid_list),
  362                     M_SYSCTLOID, M_WAITOK);
  363                 SLIST_INIT(SYSCTL_CHILDREN(oidp));
  364         } else {
  365                 oidp->oid_arg1 = arg1;
  366                 oidp->oid_arg2 = arg2;
  367         }
  368         oidp->oid_fmt = fmt;
  369         if (descr) {
  370                 int len = strlen(descr) + 1;
  371                 oidp->oid_descr = malloc(len, M_SYSCTLOID, M_WAITOK);
  372                 if (oidp->oid_descr)
  373                         strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr);
  374         };
  375         /* Update the context, if used */
  376         if (clist != NULL)
  377                 sysctl_ctx_entry_add(clist, oidp);
  378         /* Register this oid */
  379         sysctl_register_oid(oidp);
  380         return (oidp);
  381 }
  382 
  383 /*
  384  * Bulk-register all the oids in a linker_set.
  385  */
  386 void sysctl_register_set(struct linker_set *lsp)
  387 {
  388         int count = lsp->ls_length;
  389         int i;
  390         for (i = 0; i < count; i++)
  391                 sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);
  392 }
  393 
  394 void sysctl_unregister_set(struct linker_set *lsp)
  395 {
  396         int count = lsp->ls_length;
  397         int i;
  398         for (i = 0; i < count; i++)
  399                 sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]);
  400 }
  401 
  402 /*
  403  * Register the kernel's oids on startup.
  404  */
  405 extern struct linker_set sysctl_set;
  406 
  407 static void sysctl_register_all(void *arg)
  408 {
  409 
  410         sysctl_register_set(&sysctl_set);
  411 }
  412 
  413 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
  414 
  415 /*
  416  * "Staff-functions"
  417  *
  418  * These functions implement a presently undocumented interface 
  419  * used by the sysctl program to walk the tree, and get the type
  420  * so it can print the value.
  421  * This interface is under work and consideration, and should probably
  422  * be killed with a big axe by the first person who can find the time.
  423  * (be aware though, that the proper interface isn't as obvious as it
  424  * may seem, there are various conflicting requirements.
  425  *
  426  * {0,0}        printf the entire MIB-tree.
  427  * {0,1,...}    return the name of the "..." OID.
  428  * {0,2,...}    return the next OID.
  429  * {0,3}        return the OID of the name in "new"
  430  * {0,4,...}    return the kind & format info for the "..." OID.
  431  */
  432 
  433 static void
  434 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
  435 {
  436         int k;
  437         struct sysctl_oid *oidp;
  438 
  439         SLIST_FOREACH(oidp, l, oid_link) {
  440 
  441                 for (k=0; k<i; k++)
  442                         printf(" ");
  443 
  444                 printf("%d %s ", oidp->oid_number, oidp->oid_name);
  445 
  446                 printf("%c%c",
  447                         oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
  448                         oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
  449 
  450                 if (oidp->oid_handler)
  451                         printf(" *Handler");
  452 
  453                 switch (oidp->oid_kind & CTLTYPE) {
  454                         case CTLTYPE_NODE:
  455                                 printf(" Node\n");
  456                                 if (!oidp->oid_handler) {
  457                                         sysctl_sysctl_debug_dump_node(
  458                                                 oidp->oid_arg1, i+2);
  459                                 }
  460                                 break;
  461                         case CTLTYPE_INT:    printf(" Int\n"); break;
  462                         case CTLTYPE_STRING: printf(" String\n"); break;
  463                         case CTLTYPE_QUAD:   printf(" Quad\n"); break;
  464                         case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
  465                         default:             printf("\n");
  466                 }
  467 
  468         }
  469 }
  470 
  471 static int
  472 sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
  473 {
  474         int error;
  475 
  476         error = suser(req->p);
  477         if (error)
  478                 return error;
  479         sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
  480         return ENOENT;
  481 }
  482 
  483 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
  484         0, 0, sysctl_sysctl_debug, "-", "");
  485 
  486 static int
  487 sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
  488 {
  489         int *name = (int *) arg1;
  490         u_int namelen = arg2;
  491         int error = 0;
  492         struct sysctl_oid *oid;
  493         struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
  494         char buf[10];
  495 
  496         while (namelen) {
  497                 if (!lsp) {
  498                         snprintf(buf,sizeof(buf),"%d",*name);
  499                         if (req->oldidx)
  500                                 error = SYSCTL_OUT(req, ".", 1);
  501                         if (!error)
  502                                 error = SYSCTL_OUT(req, buf, strlen(buf));
  503                         if (error)
  504                                 return (error);
  505                         namelen--;
  506                         name++;
  507                         continue;
  508                 }
  509                 lsp2 = 0;
  510                 SLIST_FOREACH(oid, lsp, oid_link) {
  511                         if (oid->oid_number != *name)
  512                                 continue;
  513 
  514                         if (req->oldidx)
  515                                 error = SYSCTL_OUT(req, ".", 1);
  516                         if (!error)
  517                                 error = SYSCTL_OUT(req, oid->oid_name,
  518                                         strlen(oid->oid_name));
  519                         if (error)
  520                                 return (error);
  521 
  522                         namelen--;
  523                         name++;
  524 
  525                         if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) 
  526                                 break;
  527 
  528                         if (oid->oid_handler)
  529                                 break;
  530 
  531                         lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
  532                         break;
  533                 }
  534                 lsp = lsp2;
  535         }
  536         return (SYSCTL_OUT(req, "", 1));
  537 }
  538 
  539 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
  540 
  541 static int
  542 sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, 
  543         int *next, int *len, int level, struct sysctl_oid **oidpp)
  544 {
  545         struct sysctl_oid *oidp;
  546 
  547         *len = level;
  548         SLIST_FOREACH(oidp, lsp, oid_link) {
  549                 *next = oidp->oid_number;
  550                 *oidpp = oidp;
  551 
  552                 if (!namelen) {
  553                         if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 
  554                                 return 0;
  555                         if (oidp->oid_handler) 
  556                                 /* We really should call the handler here...*/
  557                                 return 0;
  558                         lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  559                         if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, 
  560                                 len, level+1, oidpp))
  561                                 return 0;
  562                         goto next;
  563                 }
  564 
  565                 if (oidp->oid_number < *name)
  566                         continue;
  567 
  568                 if (oidp->oid_number > *name) {
  569                         if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  570                                 return 0;
  571                         if (oidp->oid_handler)
  572                                 return 0;
  573                         lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  574                         if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, 
  575                                 next+1, len, level+1, oidpp))
  576                                 return (0);
  577                         goto next;
  578                 }
  579                 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  580                         continue;
  581 
  582                 if (oidp->oid_handler)
  583                         continue;
  584 
  585                 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  586                 if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, 
  587                         len, level+1, oidpp))
  588                         return (0);
  589         next:
  590                 namelen = 1;
  591                 *len = level;
  592         }
  593         return 1;
  594 }
  595 
  596 static int
  597 sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
  598 {
  599         int *name = (int *) arg1;
  600         u_int namelen = arg2;
  601         int i, j, error;
  602         struct sysctl_oid *oid;
  603         struct sysctl_oid_list *lsp = &sysctl__children;
  604         int newoid[CTL_MAXNAME];
  605 
  606         i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
  607         if (i)
  608                 return ENOENT;
  609         error = SYSCTL_OUT(req, newoid, j * sizeof (int));
  610         return (error);
  611 }
  612 
  613 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
  614 
  615 static int
  616 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
  617 {
  618         int i;
  619         struct sysctl_oid *oidp;
  620         struct sysctl_oid_list *lsp = &sysctl__children;
  621         char *p;
  622 
  623         if (!*name)
  624                 return ENOENT;
  625 
  626         p = name + strlen(name) - 1 ;
  627         if (*p == '.')
  628                 *p = '\0';
  629 
  630         *len = 0;
  631 
  632         for (p = name; *p && *p != '.'; p++) 
  633                 ;
  634         i = *p;
  635         if (i == '.')
  636                 *p = '\0';
  637 
  638         oidp = SLIST_FIRST(lsp);
  639 
  640         while (oidp && *len < CTL_MAXNAME) {
  641                 if (strcmp(name, oidp->oid_name)) {
  642                         oidp = SLIST_NEXT(oidp, oid_link);
  643                         continue;
  644                 }
  645                 *oid++ = oidp->oid_number;
  646                 (*len)++;
  647 
  648                 if (!i) {
  649                         if (oidpp)
  650                                 *oidpp = oidp;
  651                         return (0);
  652                 }
  653 
  654                 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
  655                         break;
  656 
  657                 if (oidp->oid_handler)
  658                         break;
  659 
  660                 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
  661                 oidp = SLIST_FIRST(lsp);
  662                 name = p+1;
  663                 for (p = name; *p && *p != '.'; p++) 
  664                                 ;
  665                 i = *p;
  666                 if (i == '.')
  667                         *p = '\0';
  668         }
  669         return ENOENT;
  670 }
  671 
  672 static int
  673 sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
  674 {
  675         char *p;
  676         int error, oid[CTL_MAXNAME], len;
  677         struct sysctl_oid *op = 0;
  678 
  679         if (!req->newlen) 
  680                 return ENOENT;
  681         if (req->newlen >= MAXPATHLEN)  /* XXX arbitrary, undocumented */
  682                 return (ENAMETOOLONG);
  683 
  684         p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
  685 
  686         error = SYSCTL_IN(req, p, req->newlen);
  687         if (error) {
  688                 free(p, M_SYSCTL);
  689                 return (error);
  690         }
  691 
  692         p [req->newlen] = '\0';
  693 
  694         error = name2oid(p, oid, &len, &op);
  695 
  696         free(p, M_SYSCTL);
  697 
  698         if (error)
  699                 return (error);
  700 
  701         error = SYSCTL_OUT(req, oid, len * sizeof *oid);
  702         return (error);
  703 }
  704 
  705 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 
  706         sysctl_sysctl_name2oid, "I", "");
  707 
  708 static int
  709 sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
  710 {
  711         struct sysctl_oid *oid;
  712         int error;
  713 
  714         error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
  715         if (error)
  716                 return (error);
  717 
  718         if (!oid->oid_fmt)
  719                 return (ENOENT);
  720         error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
  721         if (error)
  722                 return (error);
  723         error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
  724         return (error);
  725 }
  726 
  727 
  728 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
  729 
  730 static int
  731 sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
  732 {
  733         struct sysctl_oid *oid;
  734         int error;
  735 
  736         error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
  737         if (error)
  738                 return (error);
  739         
  740         if (!oid->oid_descr)
  741                 return (ENOENT);
  742         error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
  743         return (error);
  744 }
  745 
  746 SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
  747 
  748 /*
  749  * Default "handler" functions.
  750  */
  751 
  752 /*
  753  * Handle an int, signed or unsigned.
  754  * Two cases:
  755  *     a variable:  point arg1 at it.
  756  *     a constant:  pass it in arg2.
  757  */
  758 
  759 int
  760 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
  761 {
  762         int error = 0;
  763 
  764         if (arg1)
  765                 error = SYSCTL_OUT(req, arg1, sizeof(int));
  766         else
  767                 error = SYSCTL_OUT(req, &arg2, sizeof(int));
  768 
  769         if (error || !req->newptr)
  770                 return (error);
  771 
  772         if (!arg1)
  773                 error = EPERM;
  774         else
  775                 error = SYSCTL_IN(req, arg1, sizeof(int));
  776         return (error);
  777 }
  778 
  779 /*
  780  * Handle a long, signed or unsigned.  arg1 points to it.
  781  */
  782 
  783 int
  784 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
  785 {
  786         int error = 0;
  787 
  788         if (!arg1)
  789                 return (EINVAL);
  790         error = SYSCTL_OUT(req, arg1, sizeof(long));
  791 
  792         if (error || !req->newptr)
  793                 return (error);
  794 
  795         error = SYSCTL_IN(req, arg1, sizeof(long));
  796         return (error);
  797 }
  798 
  799 /*
  800  * Handle our generic '\0' terminated 'C' string.
  801  * Two cases:
  802  *      a variable string:  point arg1 at it, arg2 is max length.
  803  *      a constant string:  point arg1 at it, arg2 is zero.
  804  */
  805 
  806 int
  807 sysctl_handle_string(SYSCTL_HANDLER_ARGS)
  808 {
  809         int error=0;
  810 
  811         error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
  812 
  813         if (error || !req->newptr)
  814                 return (error);
  815 
  816         if ((req->newlen - req->newidx) >= arg2) {
  817                 error = EINVAL;
  818         } else {
  819                 arg2 = (req->newlen - req->newidx);
  820                 error = SYSCTL_IN(req, arg1, arg2);
  821                 ((char *)arg1)[arg2] = '\0';
  822         }
  823 
  824         return (error);
  825 }
  826 
  827 /*
  828  * Handle any kind of opaque data.
  829  * arg1 points to it, arg2 is the size.
  830  */
  831 
  832 int
  833 sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
  834 {
  835         int error;
  836 
  837         error = SYSCTL_OUT(req, arg1, arg2);
  838 
  839         if (error || !req->newptr)
  840                 return (error);
  841 
  842         error = SYSCTL_IN(req, arg1, arg2);
  843 
  844         return (error);
  845 }
  846 
  847 /*
  848  * Transfer functions to/from kernel space.
  849  * XXX: rather untested at this point
  850  */
  851 static int
  852 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
  853 {
  854         size_t i = 0;
  855 
  856         if (req->oldptr) {
  857                 i = l;
  858                 if (i > req->oldlen - req->oldidx)
  859                         i = req->oldlen - req->oldidx;
  860                 if (i > 0)
  861                         bcopy(p, (char *)req->oldptr + req->oldidx, i);
  862         }
  863         req->oldidx += l;
  864         if (req->oldptr && i != l)
  865                 return (ENOMEM);
  866         return (0);
  867 }
  868 
  869 static int
  870 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
  871 {
  872 
  873         if (!req->newptr)
  874                 return 0;
  875         if (req->newlen - req->newidx < l)
  876                 return (EINVAL);
  877         bcopy((char *)req->newptr + req->newidx, p, l);
  878         req->newidx += l;
  879         return (0);
  880 }
  881 
  882 int
  883 kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
  884 {
  885         int error = 0;
  886         struct sysctl_req req;
  887 
  888         bzero(&req, sizeof req);
  889 
  890         req.p = p;
  891 
  892         if (oldlenp) {
  893                 req.oldlen = *oldlenp;
  894         }
  895 
  896         if (old) {
  897                 req.oldptr= old;
  898         }
  899 
  900         if (new != NULL) {
  901                 req.newlen = newlen;
  902                 req.newptr = new;
  903         }
  904 
  905         req.oldfunc = sysctl_old_kernel;
  906         req.newfunc = sysctl_new_kernel;
  907         req.lock = 1;
  908 
  909         /* XXX this should probably be done in a general way */
  910         while (memlock.sl_lock) {
  911                 memlock.sl_want = 1;
  912                 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
  913                 memlock.sl_locked++;
  914         }
  915         memlock.sl_lock = 1;
  916 
  917         error = sysctl_root(0, name, namelen, &req);
  918 
  919         if (req.lock == 2)
  920                 vsunlock(req.oldptr, req.oldlen);
  921 
  922         memlock.sl_lock = 0;
  923 
  924         if (memlock.sl_want) {
  925                 memlock.sl_want = 0;
  926                 wakeup((caddr_t)&memlock);
  927         }
  928 
  929         if (error && error != ENOMEM)
  930                 return (error);
  931 
  932         if (retval) {
  933                 if (req.oldptr && req.oldidx > req.oldlen)
  934                         *retval = req.oldlen;
  935                 else
  936                         *retval = req.oldidx;
  937         }
  938         return (error);
  939 }
  940 
  941 int
  942 kernel_sysctlbyname(struct proc *p, char *name, void *old, size_t *oldlenp,
  943     void *new, size_t newlen, size_t *retval)
  944 {
  945         int oid[CTL_MAXNAME];
  946         size_t oidlen, plen;
  947         int error;
  948 
  949         oid[0] = 0;             /* sysctl internal magic */
  950         oid[1] = 3;             /* name2oid */
  951         oidlen = sizeof(oid);
  952 
  953         error = kernel_sysctl(p, oid, 2, oid, &oidlen,
  954             (void *)name, strlen(name), &plen);
  955         if (error)
  956                 return (error);
  957 
  958         error = kernel_sysctl(p, oid, plen / sizeof(int), old, oldlenp,
  959             new, newlen, retval);
  960         return (error);
  961 }
  962 
  963 /*
  964  * Transfer function to/from user space.
  965  */
  966 static int
  967 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
  968 {
  969         int error = 0;
  970         size_t i = 0;
  971 
  972         if (req->lock == 1 && req->oldptr) {
  973                 vslock(req->oldptr, req->oldlen);
  974                 req->lock = 2;
  975         }
  976         if (req->oldptr) {
  977                 i = l;
  978                 if (i > req->oldlen - req->oldidx)
  979                         i = req->oldlen - req->oldidx;
  980                 if (i > 0)
  981                         error = copyout(p, (char *)req->oldptr + req->oldidx,
  982                                         i);
  983         }
  984         req->oldidx += l;
  985         if (error)
  986                 return (error);
  987         if (req->oldptr && i < l)
  988                 return (ENOMEM);
  989         return (0);
  990 }
  991 
  992 static int
  993 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
  994 {
  995         int error;
  996 
  997         if (!req->newptr)
  998                 return 0;
  999         if (req->newlen - req->newidx < l)
 1000                 return (EINVAL);
 1001         error = copyin((char *)req->newptr + req->newidx, p, l);
 1002         req->newidx += l;
 1003         return (error);
 1004 }
 1005 
 1006 int
 1007 sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
 1008     int *nindx, struct sysctl_req *req)
 1009 {
 1010         struct sysctl_oid *oid;
 1011         int indx;
 1012 
 1013         oid = SLIST_FIRST(&sysctl__children);
 1014         indx = 0;
 1015         while (oid && indx < CTL_MAXNAME) {
 1016                 if (oid->oid_number == name[indx]) {
 1017                         indx++;
 1018                         if (oid->oid_kind & CTLFLAG_NOLOCK)
 1019                                 req->lock = 0;
 1020                         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
 1021                                 if (oid->oid_handler != NULL ||
 1022                                     indx == namelen) {
 1023                                         *noid = oid;
 1024                                         if (nindx != NULL)
 1025                                                 *nindx = indx;
 1026                                         return (0);
 1027                                 }
 1028                                 oid = SLIST_FIRST(
 1029                                     (struct sysctl_oid_list *)oid->oid_arg1);
 1030                         } else if (indx == namelen) {
 1031                                 *noid = oid;
 1032                                 if (nindx != NULL)
 1033                                         *nindx = indx;
 1034                                 return (0);
 1035                         } else {
 1036                                 return (ENOTDIR);
 1037                         }
 1038                 } else {
 1039                         oid = SLIST_NEXT(oid, oid_link);
 1040                 }
 1041         }
 1042         return (ENOENT);
 1043 }
 1044 
 1045 /*
 1046  * Traverse our tree, and find the right node, execute whatever it points
 1047  * to, and return the resulting error code.
 1048  */
 1049 
 1050 int
 1051 sysctl_root(SYSCTL_HANDLER_ARGS)
 1052 {
 1053         struct sysctl_oid *oid;
 1054         int error, indx;
 1055 
 1056         error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
 1057         if (error)
 1058                 return (error);
 1059 
 1060         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
 1061                 /*
 1062                  * You can't call a sysctl when it's a node, but has
 1063                  * no handler.  Inform the user that it's a node.
 1064                  * The indx may or may not be the same as namelen.
 1065                  */
 1066                 if (oid->oid_handler == NULL)
 1067                         return (EISDIR);
 1068         }
 1069 
 1070         /* If writing isn't allowed */
 1071         if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
 1072             ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
 1073                 return (EPERM);
 1074 
 1075         /* Most likely only root can write */
 1076         if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
 1077             req->newptr && req->p &&
 1078             (error = suser_xxx(0, req->p, 
 1079             (oid->oid_kind & CTLFLAG_PRISON) ? PRISON_ROOT : 0)))
 1080                 return (error);
 1081 
 1082         if (!oid->oid_handler)
 1083                 return EINVAL;
 1084 
 1085         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
 1086                 error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
 1087                     req);
 1088         else
 1089                 error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
 1090                     req);
 1091         return (error);
 1092 }
 1093 
 1094 #ifndef _SYS_SYSPROTO_H_
 1095 struct sysctl_args {
 1096         int     *name;
 1097         u_int   namelen;
 1098         void    *old;
 1099         size_t  *oldlenp;
 1100         void    *new;
 1101         size_t  newlen;
 1102 };
 1103 #endif
 1104 
 1105 int
 1106 __sysctl(struct proc *p, struct sysctl_args *uap)
 1107 {
 1108         int error, i, name[CTL_MAXNAME];
 1109         size_t j;
 1110 
 1111         if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
 1112                 return (EINVAL);
 1113 
 1114         error = copyin(uap->name, &name, uap->namelen * sizeof(int));
 1115         if (error)
 1116                 return (error);
 1117 
 1118         error = userland_sysctl(p, name, uap->namelen,
 1119                 uap->old, uap->oldlenp, 0,
 1120                 uap->new, uap->newlen, &j);
 1121         if (error && error != ENOMEM)
 1122                 return (error);
 1123         if (uap->oldlenp) {
 1124                 i = copyout(&j, uap->oldlenp, sizeof(j));
 1125                 if (i)
 1126                         return (i);
 1127         }
 1128         return (error);
 1129 }
 1130 
 1131 /*
 1132  * This is used from various compatibility syscalls too.  That's why name
 1133  * must be in kernel space.
 1134  */
 1135 int
 1136 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)
 1137 {
 1138         int error = 0;
 1139         struct sysctl_req req, req2;
 1140 
 1141         bzero(&req, sizeof req);
 1142 
 1143         req.p = p;
 1144 
 1145         if (oldlenp) {
 1146                 if (inkernel) {
 1147                         req.oldlen = *oldlenp;
 1148                 } else {
 1149                         error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
 1150                         if (error)
 1151                                 return (error);
 1152                 }
 1153         }
 1154 
 1155         if (old) {
 1156                 if (!useracc(old, req.oldlen, VM_PROT_WRITE))
 1157                         return (EFAULT);
 1158                 req.oldptr= old;
 1159         }
 1160 
 1161         if (new != NULL) {
 1162                 if (!useracc(new, req.newlen, VM_PROT_READ))
 1163                         return (EFAULT);
 1164                 req.newlen = newlen;
 1165                 req.newptr = new;
 1166         }
 1167 
 1168         req.oldfunc = sysctl_old_user;
 1169         req.newfunc = sysctl_new_user;
 1170         req.lock = 1;
 1171 
 1172         /* XXX this should probably be done in a general way */
 1173         while (memlock.sl_lock) {
 1174                 memlock.sl_want = 1;
 1175                 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
 1176                 memlock.sl_locked++;
 1177         }
 1178         memlock.sl_lock = 1;
 1179 
 1180         do {
 1181             req2 = req;
 1182             error = sysctl_root(0, name, namelen, &req2);
 1183         } while (error == EAGAIN);
 1184 
 1185         req = req2;
 1186         if (req.lock == 2)
 1187                 vsunlock(req.oldptr, req.oldlen);
 1188 
 1189         memlock.sl_lock = 0;
 1190 
 1191         if (memlock.sl_want) {
 1192                 memlock.sl_want = 0;
 1193                 wakeup((caddr_t)&memlock);
 1194         }
 1195 
 1196         if (error && error != ENOMEM)
 1197                 return (error);
 1198 
 1199         if (retval) {
 1200                 if (req.oldptr && req.oldidx > req.oldlen)
 1201                         *retval = req.oldlen;
 1202                 else
 1203                         *retval = req.oldidx;
 1204         }
 1205         return (error);
 1206 }
 1207 
 1208 #ifdef COMPAT_43
 1209 #include <sys/socket.h>
 1210 #include <vm/vm_param.h>
 1211 
 1212 #define KINFO_PROC              (0<<8)
 1213 #define KINFO_RT                (1<<8)
 1214 #define KINFO_VNODE             (2<<8)
 1215 #define KINFO_FILE              (3<<8)
 1216 #define KINFO_METER             (4<<8)
 1217 #define KINFO_LOADAVG           (5<<8)
 1218 #define KINFO_CLOCKRATE         (6<<8)
 1219 
 1220 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
 1221 #define KINFO_BSDI_SYSINFO      (101<<8)
 1222 
 1223 /*
 1224  * XXX this is bloat, but I hope it's better here than on the potentially
 1225  * limited kernel stack...  -Peter
 1226  */
 1227 
 1228 static struct {
 1229         int     bsdi_machine;           /* "i386" on BSD/386 */
 1230 /*      ^^^ this is an offset to the string, relative to the struct start */
 1231         char    *pad0;
 1232         long    pad1;
 1233         long    pad2;
 1234         long    pad3;
 1235         u_long  pad4;
 1236         u_long  pad5;
 1237         u_long  pad6;
 1238 
 1239         int     bsdi_ostype;            /* "BSD/386" on BSD/386 */
 1240         int     bsdi_osrelease;         /* "1.1" on BSD/386 */
 1241         long    pad7;
 1242         long    pad8;
 1243         char    *pad9;
 1244 
 1245         long    pad10;
 1246         long    pad11;
 1247         int     pad12;
 1248         long    pad13;
 1249         quad_t  pad14;
 1250         long    pad15;
 1251 
 1252         struct  timeval pad16;
 1253         /* we dont set this, because BSDI's uname used gethostname() instead */
 1254         int     bsdi_hostname;          /* hostname on BSD/386 */
 1255 
 1256         /* the actual string data is appended here */
 1257 
 1258 } bsdi_si;
 1259 /*
 1260  * this data is appended to the end of the bsdi_si structure during copyout.
 1261  * The "char *" offsets are relative to the base of the bsdi_si struct.
 1262  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
 1263  * should not exceed the length of the buffer here... (or else!! :-)
 1264  */
 1265 static char bsdi_strings[80];   /* It had better be less than this! */
 1266 
 1267 #ifndef _SYS_SYSPROTO_H_
 1268 struct getkerninfo_args {
 1269         int     op;
 1270         char    *where;
 1271         size_t  *size;
 1272         int     arg;
 1273 };
 1274 #endif
 1275 
 1276 int
 1277 ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
 1278 {
 1279         int error, name[6];
 1280         size_t size;
 1281 
 1282         switch (uap->op & 0xff00) {
 1283 
 1284         case KINFO_RT:
 1285                 name[0] = CTL_NET;
 1286                 name[1] = PF_ROUTE;
 1287                 name[2] = 0;
 1288                 name[3] = (uap->op & 0xff0000) >> 16;
 1289                 name[4] = uap->op & 0xff;
 1290                 name[5] = uap->arg;
 1291                 error = userland_sysctl(p, name, 6, uap->where, uap->size,
 1292                         0, 0, 0, &size);
 1293                 break;
 1294 
 1295         case KINFO_VNODE:
 1296                 name[0] = CTL_KERN;
 1297                 name[1] = KERN_VNODE;
 1298                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1299                         0, 0, 0, &size);
 1300                 break;
 1301 
 1302         case KINFO_PROC:
 1303                 name[0] = CTL_KERN;
 1304                 name[1] = KERN_PROC;
 1305                 name[2] = uap->op & 0xff;
 1306                 name[3] = uap->arg;
 1307                 error = userland_sysctl(p, name, 4, uap->where, uap->size,
 1308                         0, 0, 0, &size);
 1309                 break;
 1310 
 1311         case KINFO_FILE:
 1312                 name[0] = CTL_KERN;
 1313                 name[1] = KERN_FILE;
 1314                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1315                         0, 0, 0, &size);
 1316                 break;
 1317 
 1318         case KINFO_METER:
 1319                 name[0] = CTL_VM;
 1320                 name[1] = VM_METER;
 1321                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1322                         0, 0, 0, &size);
 1323                 break;
 1324 
 1325         case KINFO_LOADAVG:
 1326                 name[0] = CTL_VM;
 1327                 name[1] = VM_LOADAVG;
 1328                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1329                         0, 0, 0, &size);
 1330                 break;
 1331 
 1332         case KINFO_CLOCKRATE:
 1333                 name[0] = CTL_KERN;
 1334                 name[1] = KERN_CLOCKRATE;
 1335                 error = userland_sysctl(p, name, 2, uap->where, uap->size,
 1336                         0, 0, 0, &size);
 1337                 break;
 1338 
 1339         case KINFO_BSDI_SYSINFO: {
 1340                 /*
 1341                  * this is pretty crude, but it's just enough for uname()
 1342                  * from BSDI's 1.x libc to work.
 1343                  *
 1344                  * In particular, it doesn't return the same results when
 1345                  * the supplied buffer is too small.  BSDI's version apparently
 1346                  * will return the amount copied, and set the *size to how
 1347                  * much was needed.  The emulation framework here isn't capable
 1348                  * of that, so we just set both to the amount copied.
 1349                  * BSDI's 2.x product apparently fails with ENOMEM in this
 1350                  * scenario.
 1351                  */
 1352 
 1353                 u_int needed;
 1354                 u_int left;
 1355                 char *s;
 1356 
 1357                 bzero((char *)&bsdi_si, sizeof(bsdi_si));
 1358                 bzero(bsdi_strings, sizeof(bsdi_strings));
 1359 
 1360                 s = bsdi_strings;
 1361 
 1362                 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
 1363                 strcpy(s, ostype);
 1364                 s += strlen(s) + 1;
 1365 
 1366                 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
 1367                 strcpy(s, osrelease);
 1368                 s += strlen(s) + 1;
 1369 
 1370                 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
 1371                 strcpy(s, machine);
 1372                 s += strlen(s) + 1;
 1373 
 1374                 needed = sizeof(bsdi_si) + (s - bsdi_strings);
 1375 
 1376                 if (uap->where == NULL) {
 1377                         /* process is asking how much buffer to supply.. */
 1378                         size = needed;
 1379                         error = 0;
 1380                         break;
 1381                 }
 1382 
 1383 
 1384                 /* if too much buffer supplied, trim it down */
 1385                 if (size > needed)
 1386                         size = needed;
 1387 
 1388                 /* how much of the buffer is remaining */
 1389                 left = size;
 1390 
 1391                 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
 1392                         break;
 1393 
 1394                 /* is there any point in continuing? */
 1395                 if (left > sizeof(bsdi_si)) {
 1396                         left -= sizeof(bsdi_si);
 1397                         error = copyout(&bsdi_strings,
 1398                                         uap->where + sizeof(bsdi_si), left);
 1399                 }
 1400                 break;
 1401         }
 1402 
 1403         default:
 1404                 return (EOPNOTSUPP);
 1405         }
 1406         if (error)
 1407                 return (error);
 1408         p->p_retval[0] = size;
 1409         if (uap->size)
 1410                 error = copyout((caddr_t)&size, (caddr_t)uap->size,
 1411                     sizeof(size));
 1412         return (error);
 1413 }
 1414 #endif /* COMPAT_43 */

Cache object: 84ee4020f72f60d672625e0db0ea56f3


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