root/usr/src/common/mdesc/mdesc_init_intern.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/mdesc.h>
#include <sys/mdesc_impl.h>

md_t *
md_init_intern(uint64_t *ptr,  void *(*allocp)(size_t),
            void (*freep)(void *, size_t))
{
        md_impl_t       *mdp;
        int             idx;
        int             count;
        int             done;
        uint64_t        gen;
        mde_str_cookie_t root_name;

        /*
         * Very basic checkup for alignment to avoid
         * bus error issues.
         */
        if ((((uintptr_t)ptr) & 7) != 0)
                return (NULL);

        mdp = (md_impl_t *)allocp(sizeof (md_impl_t));

        if (mdp == NULL)
                return (NULL);

        mdp->allocp = allocp;
        mdp->freep = freep;

        mdp->caddr = (char *)ptr;

        /*
         * setup internal structures
         */

        mdp->headerp = (md_header_t *)mdp->caddr;

        if (mdtoh32(mdp->headerp->transport_version) != MD_TRANSPORT_VERSION) {
                goto cleanup_nohash;
        }

        mdp->node_blk_size = mdtoh32(mdp->headerp->node_blk_sz);
        mdp->name_blk_size = mdtoh32(mdp->headerp->name_blk_sz);
        mdp->data_blk_size = mdtoh32(mdp->headerp->data_blk_sz);

        mdp->size = MD_HEADER_SIZE + mdp->node_blk_size +
            mdp->name_blk_size + mdp->data_blk_size;

        mdp->mdep = (md_element_t *)(mdp->caddr + MD_HEADER_SIZE);
        mdp->namep = (char *)(mdp->caddr + MD_HEADER_SIZE + mdp->node_blk_size);
        mdp->datap = (uint8_t *)(mdp->caddr + MD_HEADER_SIZE +
            mdp->name_blk_size + mdp->node_blk_size);

        mdp->root_node = MDE_INVAL_ELEM_COOKIE;


        /*
         * Should do a lot more sanity checking here.
         */

        /*
         * Should initialize a name hash here if we intend to use one
         */

        /*
         * Setup to find the root node
         */
        root_name = md_find_name((md_t *)mdp, "root");
        if (root_name == MDE_INVAL_STR_COOKIE) {
                goto cleanup;
        }

        /*
         * One more property we need is the count of nodes in the
         * DAG, not just the number of elements.
         *
         * We try and pickup the root node along the way here.
         */

        for (done = 0, idx = 0, count = 0; !done; ) {
                md_element_t *np;

                np = &(mdp->mdep[idx]);

                switch (MDE_TAG(np)) {
                case MDET_LIST_END:
                        done = 1;
                        break;

                case MDET_NODE:
                        if (root_name == MDE_NAME(np)) {
                                if (mdp->root_node != MDE_INVAL_ELEM_COOKIE) {
                                        /* Gah .. more than one root */
                                        goto cleanup;
                                }
                                mdp->root_node = (mde_cookie_t)idx;
                        }
                        idx = MDE_PROP_INDEX(np);
                        count++;
                        break;

                default:
                        idx++;  /* ignore */
                }
        }

        /*
         * Ensure there is a root node
         */
        if (mdp->root_node == MDE_INVAL_ELEM_COOKIE) {
                goto cleanup;
        }

        /*
         * Register the counts
         */

        mdp->element_count = idx + 1;   /* include LIST_END */
        mdp->node_count = count;

        /*
         * Final sanity check that everything adds up
         */
        if (mdp->element_count != (mdp->node_blk_size / MD_ELEMENT_SIZE))
                goto cleanup;

        mdp->md_magic = LIBMD_MAGIC;

        /*
         * Setup MD generation
         */
        if (md_get_prop_val((md_t *)mdp, mdp->root_node,
            "md-generation#", &gen) != 0)
                mdp->gen = MDESC_INVAL_GEN;
        else
                mdp->gen = gen;

        return ((md_t *)mdp);

cleanup:
        /*
         * Clean up here - including a name hash if
         * we build one.
         */

cleanup_nohash:
        mdp->freep(mdp, sizeof (md_impl_t));
        return (NULL);
}