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