Annotation of XNU/bsd/kern/kern_newsysctl.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.